Multi-line svn commit, see body.
[shibboleth/cpp-opensaml.git] / saml / saml2 / binding / impl / SAML2Redirect.cpp
1 /*
2  *  Copyright 2001-2007 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * @file saml/saml2/binding/SAML2Redirect.h
19  * 
20  * SAML 2.0 HTTP Redirect compression functionality
21  */
22
23 #include "internal.h"
24 #include "saml2/binding/SAML2Redirect.h"
25
26 #include <zlib.h>
27 #include <log4cpp/Category.hh>
28 #include <xmltooling/util/NDC.h>
29
30 using namespace log4cpp;
31 using namespace std;
32
33 namespace {
34     extern "C" {
35         voidpf saml_zalloc(void* opaque, uInt items, uInt size)
36         {
37             return malloc(items*size);
38         }
39         
40         void saml_zfree(void* opaque, voidpf addr)
41         {
42             free(addr);
43         }
44     };
45 };
46
47 char* opensaml::saml2p::deflate(char* in, unsigned int in_len, unsigned int* out_len)
48 {
49 #ifdef _DEBUG
50     xmltooling::NDC ndc("deflate");
51 #endif
52     Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2Redirect.zlib");
53
54     z_stream z;
55     memset(&z, 0, sizeof(z_stream));
56     
57     z.zalloc = saml_zalloc;
58     z.zfree = saml_zfree;
59     z.opaque = NULL;
60     z.next_in = (Bytef*)in;
61     z.avail_in = in_len;
62     *out_len = 0;
63
64     int ret = deflateInit2(&z, 9, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY);
65     if (ret != Z_OK) {
66         log.error("zlib deflateInit2 failed with error code (%d)", ret);
67         return NULL;
68     }
69   
70     int dlen = in_len + (in_len >> 8) + 12;  /* orig_size * 1.001 + 12 */
71     char* out = new char[dlen];
72     z.next_out = (Bytef*)out;
73     z.avail_out = dlen;
74   
75     ret = deflate(&z, Z_FINISH);
76     if (ret != Z_STREAM_END) {
77     deflateEnd(&z);
78         log.error("zlib deflateInit2 failed with error code (%d)", ret);
79         delete[] out;
80     }
81   
82     *out_len = z.total_out;
83     deflateEnd(&z);
84     return out;
85 }
86
87 unsigned int opensaml::saml2p::inflate(char* in, unsigned int in_len, ostream& out)
88 {
89 #ifdef _DEBUG
90     xmltooling::NDC ndc("inflate");
91 #endif
92     Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2Redirect.zlib");
93
94     z_stream z;
95     memset(&z, 0, sizeof(z_stream));
96     
97     z.zalloc = saml_zalloc;
98     z.zfree = saml_zfree;
99     z.opaque = NULL;
100     z.next_in = (Bytef*)in;
101     z.avail_in = in_len;
102   
103     int dlen = in_len << 3;  /* guess inflated size: orig_size * 8 */
104     Byte* buf = new Byte[dlen];
105     memset(buf, 0, dlen);
106     z.next_out = buf;
107     z.avail_out = dlen;
108   
109     int ret = inflateInit2(&z, -15);
110     if (ret != Z_OK) {
111         log.error("zlib inflateInit2 failed with error code (%d)", ret);
112         delete[] buf;
113         return 0;
114     }
115   
116     int iter = 30;
117     while (--iter) {  /* Make sure we can never be caught in infinite loop */
118         ret = inflate(&z, Z_SYNC_FLUSH);
119         switch (ret) {
120             case Z_STREAM_END:
121                 ret = z.next_out - buf;
122                 z.next_out = buf;
123                 while (ret--)
124                     out << *(z.next_out++);
125                 goto done;
126                 
127             case Z_OK:  /* avail_out should be 0 now. Time to dump the buffer. */
128                 ret = z.next_out - buf;
129                 z.next_out = buf;
130                 while (ret--)
131                     out << *(z.next_out++);
132                 memset(buf, 0, dlen);
133                 z.next_out = buf;
134                 z.avail_out = dlen;
135                 break;
136               
137             default:
138                 delete[] buf;
139                 inflateEnd(&z);
140                 log.error("zlib inflate failed with error code (%d)", ret);
141                 return 0;
142         }
143     }
144 done:
145     delete[] buf;
146     int out_len = z.total_out;
147     inflateEnd(&z);
148     return out_len;
149 }