Coverage Report

Created: 2026-02-11 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xerces-c/src/xercesc/util/NetAccessors/BinHTTPInputStreamCommon.cpp
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
/*
19
 * $Id: BinFileInputStream.cpp 553903 2007-07-06 14:43:42Z amassari $
20
 */
21
22
23
// ---------------------------------------------------------------------------
24
//  Includes
25
// ---------------------------------------------------------------------------
26
27
#if HAVE_CONFIG_H
28
#  include <config.h>
29
#endif
30
31
#include <stdlib.h>
32
#include <string.h>
33
34
#include <xercesc/util/NetAccessors/BinHTTPInputStreamCommon.hpp>
35
36
#include <xercesc/util/XMLString.hpp>
37
#include <xercesc/util/XMLExceptMsgs.hpp>
38
#include <xercesc/util/Janitor.hpp>
39
#include <xercesc/util/TransService.hpp>
40
#include <xercesc/util/PlatformUtils.hpp>
41
#include <xercesc/util/Base64.hpp>
42
43
XERCES_CPP_NAMESPACE_BEGIN
44
45
BinHTTPInputStreamCommon::BinHTTPInputStreamCommon(MemoryManager *manager)
46
213
      : fBytesProcessed(0)
47
213
      , fBuffer(1023, manager)
48
213
    , fBufferPos(0)
49
213
      , fContentType(0)
50
213
    , fEncoding(0)
51
213
      , fMemoryManager(manager)
52
213
{
53
213
}
54
55
56
BinHTTPInputStreamCommon::~BinHTTPInputStreamCommon()
57
213
{
58
213
    if(fContentType) fMemoryManager->deallocate(fContentType);
59
213
    if(fEncoding) fMemoryManager->deallocate(fEncoding);
60
213
}
61
62
static const char *CRLF = "\r\n";
63
64
void BinHTTPInputStreamCommon::createHTTPRequest(const XMLURL &urlSource, const XMLNetHTTPInfo *httpInfo, CharBuffer &buffer)
65
0
{
66
0
    static const char *GET = "GET ";
67
0
    static const char *PUT = "PUT ";
68
0
    static const char *POST = "POST ";
69
0
    static const char *HTTP10 = " HTTP/1.0\r\n";
70
0
    static const char *HOST = "Host: ";
71
0
    static const char *AUTHORIZATION = "Authorization: Basic ";
72
0
    static const char *COLON = ":";
73
74
0
    XMLTransService::Codes failReason;
75
0
    const XMLSize_t blockSize = 2048;
76
77
0
    XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor("ISO8859-1", failReason, blockSize, fMemoryManager);
78
0
    Janitor<XMLTranscoder> janTrans(trans);
79
80
0
    TranscodeToStr hostName(urlSource.getHost(), trans, fMemoryManager);
81
0
    TranscodeToStr path(urlSource.getPath(), trans, fMemoryManager);
82
0
    TranscodeToStr fragment(urlSource.getFragment(), trans, fMemoryManager);
83
0
    TranscodeToStr query(urlSource.getQuery(), trans, fMemoryManager);
84
85
    // Build up the http GET command to send to the server.
86
    // To do:  We should really support http 1.1.  This implementation
87
    //         is weak.
88
0
    if(httpInfo) {
89
0
        switch(httpInfo->fHTTPMethod) {
90
0
        case XMLNetHTTPInfo::GET:   buffer.append(GET); break;
91
0
        case XMLNetHTTPInfo::PUT:   buffer.append(PUT); break;
92
0
        case XMLNetHTTPInfo::POST:  buffer.append(POST); break;
93
0
        }
94
0
    }
95
0
    else {
96
0
        buffer.append(GET);
97
0
    }
98
99
0
    if(path.str() != 0) {
100
0
        buffer.append((char*)path.str());
101
0
    }
102
0
    else {
103
0
        buffer.append("/");
104
0
    }
105
106
0
    if(query.str() != 0) {
107
0
        buffer.append("?");
108
0
        buffer.append((char*)query.str());
109
0
    }
110
111
0
    if(fragment.str() != 0) {
112
0
        buffer.append((char*)fragment.str());
113
0
    }
114
0
    buffer.append(HTTP10);
115
116
0
    buffer.append(HOST);
117
0
    buffer.append((char*)hostName.str());
118
0
    if(urlSource.getPortNum() != 80)
119
0
    {
120
0
        buffer.append(COLON);
121
0
        buffer.appendDecimalNumber(urlSource.getPortNum());
122
0
    }
123
0
    buffer.append(CRLF);
124
125
0
    const XMLCh *username = urlSource.getUser();
126
0
    const XMLCh *password = urlSource.getPassword();
127
0
    if(username && password) {
128
0
        XMLBuffer userPassBuf(256, fMemoryManager);
129
0
        userPassBuf.append(username);
130
0
        userPassBuf.append(chColon);
131
0
        userPassBuf.append(password);
132
133
0
        TranscodeToStr userPass(userPassBuf.getRawBuffer(), trans, fMemoryManager);
134
135
0
        XMLSize_t len;
136
0
        XMLByte* encodedData = Base64::encode(userPass.str(), userPass.length(), &len, fMemoryManager);
137
0
        ArrayJanitor<XMLByte> janBuf2(encodedData, fMemoryManager);
138
139
0
        if(encodedData) {
140
            // HTTP doesn't want the 0x0A separating the data in chunks of 76 chars per line
141
0
            XMLByte* authData = (XMLByte*)fMemoryManager->allocate((len+1)*sizeof(XMLByte));
142
0
            ArrayJanitor<XMLByte> janBuf(authData, fMemoryManager);
143
0
            XMLByte *cursor = authData;
144
0
            for(XMLSize_t i = 0; i < len; ++i)
145
0
                if(encodedData[i] != chLF)
146
0
                    *cursor++ = encodedData[i];
147
0
            *cursor++ = 0;
148
0
            buffer.append(AUTHORIZATION);
149
0
            buffer.append((char*)authData);
150
0
            buffer.append(CRLF);
151
0
        }
152
0
    }
153
154
0
    if(httpInfo && httpInfo->fHeaders)
155
0
        buffer.append(httpInfo->fHeaders, httpInfo->fHeadersLen);
156
157
0
    buffer.append(CRLF);
158
0
}
159
160
XMLCh *BinHTTPInputStreamCommon::findHeader(const char *name)
161
0
{
162
0
    XMLSize_t len = strlen(name);
163
164
0
    char *p = strstr(fBuffer.getRawBuffer(), name);
165
0
    while(p != 0) {
166
0
        if(*(p - 1) == '\n' &&
167
0
            *(p + len) == ':' &&
168
0
            *(p + len + 1) == ' ') {
169
170
0
            p += len + 2;
171
172
0
            char *endP = strstr(p, CRLF);
173
0
            if(endP == 0) {
174
0
                for(endP = p; *endP != 0; ++endP) ;
175
0
            }
176
177
            // Transcode from iso-8859-1
178
0
            TranscodeFromStr value((XMLByte*)p, endP - p, "ISO8859-1", fMemoryManager);
179
0
            return value.adopt();
180
0
        }
181
182
0
        p = strstr(p + 1, name);
183
0
    }
184
185
0
    return 0;
186
0
}
187
188
int BinHTTPInputStreamCommon::sendRequest(const XMLURL &url, const XMLNetHTTPInfo *httpInfo)
189
0
{
190
    //
191
    //  Constants in ASCII to send/check in the HTTP request/response
192
    //
193
194
0
    static const char *CRLF2X = "\r\n\r\n";
195
0
    static const char *LF2X = "\n\n";
196
197
    // The port is open and ready to go.
198
    // Build up the http GET command to send to the server.
199
0
    CharBuffer requestBuffer(1023, fMemoryManager);
200
0
    createHTTPRequest(url, httpInfo, requestBuffer);
201
202
    // Send the http request
203
0
    if(!send(requestBuffer.getRawBuffer(), requestBuffer.getLen())) {
204
0
        ThrowXMLwithMemMgr1(NetAccessorException,
205
0
                            XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager);
206
0
    }
207
208
0
    if(httpInfo && httpInfo->fPayload) {
209
0
        if(!send(httpInfo->fPayload, httpInfo->fPayloadLen)) {
210
0
            ThrowXMLwithMemMgr1(NetAccessorException,
211
0
                                XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager);
212
0
        }
213
0
    }
214
215
    //
216
    // get the response, check the http header for errors from the server.
217
    //
218
0
    char tmpBuf[1024];
219
0
    int ret;
220
221
0
    fBuffer.reset();
222
0
    while(true) {
223
0
        ret = receive(tmpBuf, sizeof(tmpBuf));
224
0
        if(ret == -1) {
225
0
            ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager);
226
0
        }
227
228
        // connection closed
229
0
        if(ret == 0)
230
0
            break;
231
232
0
        fBuffer.append(tmpBuf, ret);
233
234
0
        fBufferPos = strstr(fBuffer.getRawBuffer(), CRLF2X);
235
0
        if(fBufferPos != 0) {
236
0
            fBufferPos += 4;
237
0
            *(fBufferPos - 2) = 0;
238
0
            break;
239
0
        }
240
241
0
        fBufferPos = strstr(fBuffer.getRawBuffer(), LF2X);
242
0
        if(fBufferPos != 0) {
243
0
            fBufferPos += 2;
244
0
            *(fBufferPos - 1) = 0;
245
0
            break;
246
0
        }
247
0
    }
248
249
    // Parse the response status
250
0
    char *p = strstr(fBuffer.getRawBuffer(), "HTTP");
251
0
    if(p == 0) {
252
0
        ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager);
253
0
    }
254
255
0
    p = strchr(p, chSpace);
256
0
    if(p == 0) {
257
0
        ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager);
258
0
    }
259
260
0
    return atoi(p);
261
0
}
262
263
const XMLCh *BinHTTPInputStreamCommon::getContentType() const
264
0
{
265
0
    if(fContentType == 0) {
266
        // mutable
267
0
        const_cast<BinHTTPInputStreamCommon*>(this)->fContentType =
268
0
        const_cast<BinHTTPInputStreamCommon*>(this)->findHeader("Content-Type");
269
0
    }
270
0
    return fContentType;
271
0
}
272
273
const XMLCh *BinHTTPInputStreamCommon::getEncoding() const
274
0
{
275
0
  if(fEncoding == 0) {
276
0
    const XMLCh* contentTypeHeader = getContentType();
277
0
    if(contentTypeHeader)
278
0
    {
279
0
      const XMLCh szCharsetEquals[] = {chLatin_c, chLatin_h, chLatin_a, chLatin_r, chLatin_s, chLatin_e, chLatin_t, chEqual, chNull };
280
281
0
      BaseRefVectorOf<XMLCh>* tokens=XMLString::tokenizeString(contentTypeHeader, chSemiColon, fMemoryManager);
282
0
      for(XMLSize_t i=0;i<tokens->size();i++)
283
0
      {
284
0
        XMLString::removeWS(tokens->elementAt(i), fMemoryManager);
285
0
        if(XMLString::startsWithI(tokens->elementAt(i), szCharsetEquals))
286
0
        {
287
          // mutable
288
0
          const XMLCh* encodingName=tokens->elementAt(i)+XMLString::stringLen(szCharsetEquals);
289
0
          const_cast<BinHTTPInputStreamCommon*>(this)->fEncoding = XMLString::replicate(encodingName, fMemoryManager);
290
0
          break;
291
0
        }
292
0
      }
293
      // if the charset=value entry was not present, check if we should use a default value
294
0
      if(fEncoding==0 && tokens->size()>0)
295
0
      {
296
0
        const XMLCh szTextSlash[] = { chLatin_t, chLatin_e, chLatin_x, chLatin_t, chForwardSlash, chNull };
297
0
        const XMLCh szXml[] = {chLatin_x, chLatin_m, chLatin_l, chNull };
298
0
        const XMLCh szXmlDash[] = {chLatin_x, chLatin_m, chLatin_l, chDash, chNull };
299
300
0
        XMLBuffer contentType(XMLString::stringLen(contentTypeHeader), fMemoryManager);
301
0
        contentType.set(tokens->elementAt(0));
302
303
0
        XMLCh* strType = contentType.getRawBuffer();
304
0
        XMLString::removeWS(strType, fMemoryManager);
305
0
        if(XMLString::startsWithI(strType, szTextSlash))
306
0
        {
307
          // text/* has a default encoding of iso-8859-1
308
          
309
          // text/xml, text/xml-external-parsed-entity, or a subtype like text/AnythingAtAll+xml 
310
          // has a default encoding of us-ascii
311
0
          XMLCh* subType = strType+XMLString::stringLen(szTextSlash);
312
313
0
          BaseRefVectorOf<XMLCh>* tokens=XMLString::tokenizeString(subType, chPlus, fMemoryManager);
314
0
          for(XMLSize_t i=0;i<tokens->size();i++)
315
0
          {
316
0
            XMLCh* part=tokens->elementAt(i);
317
0
            if(XMLString::compareIStringASCII(part, szXml)==0 || XMLString::startsWithI(part, szXmlDash))
318
0
            {
319
0
              const_cast<BinHTTPInputStreamCommon*>(this)->fEncoding = XMLString::replicate(XMLUni::fgUSASCIIEncodingString, fMemoryManager);
320
0
              break;
321
0
            }
322
0
          }
323
0
          if(fEncoding==0)
324
0
            const_cast<BinHTTPInputStreamCommon*>(this)->fEncoding = XMLString::replicate(XMLUni::fgISO88591EncodingString, fMemoryManager);
325
0
          delete tokens;
326
0
        }
327
0
      }
328
0
      delete tokens;
329
0
    }
330
0
  }
331
0
    return fEncoding;
332
0
}
333
334
XMLSize_t BinHTTPInputStreamCommon::readBytes(XMLByte* const    toFill,
335
                                              const XMLSize_t    maxToRead)
336
0
{
337
0
    XMLSize_t len = fBuffer.getRawBuffer() + fBuffer.getLen() - fBufferPos;
338
0
    if(len > 0)
339
0
    {
340
        // If there's any data left over in the buffer into which we first
341
        //   read from the server (to get the http header), return that.
342
0
        if (len > maxToRead)
343
0
            len = maxToRead;
344
0
        memcpy(toFill, fBufferPos, len);
345
0
        fBufferPos += len;
346
0
    }
347
0
    else
348
0
    {
349
        // There was no data in the local buffer.
350
        // Read some from the socket, straight into our caller's buffer.
351
        //
352
0
        int cbRead = receive((char *)toFill, maxToRead);
353
0
        if (cbRead == -1)
354
0
        {
355
0
            ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, fMemoryManager);
356
0
        }
357
0
        len = cbRead;
358
0
    }
359
360
0
    fBytesProcessed += len;
361
0
    return len;
362
0
}
363
364
XERCES_CPP_NAMESPACE_END