GME  13
BinHTTPInputStreamCommon.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /*
00019  * $Id: BinFileInputStream.cpp 553903 2007-07-06 14:43:42Z amassari $
00020  */
00021 
00022 
00023 // ---------------------------------------------------------------------------
00024 //  Includes
00025 // ---------------------------------------------------------------------------
00026 
00027 #if HAVE_CONFIG_H
00028 #  include <config.h>
00029 #endif
00030 
00031 #include <stdlib.h>
00032 #include <string.h>
00033 
00034 #include <xercesc/util/NetAccessors/BinHTTPInputStreamCommon.hpp>
00035 
00036 #include <xercesc/util/XMLString.hpp>
00037 #include <xercesc/util/XMLExceptMsgs.hpp>
00038 #include <xercesc/util/Janitor.hpp>
00039 #include <xercesc/util/TransService.hpp>
00040 #include <xercesc/util/PlatformUtils.hpp>
00041 #include <xercesc/util/Base64.hpp>
00042 
00043 XERCES_CPP_NAMESPACE_BEGIN
00044 
00045 BinHTTPInputStreamCommon::BinHTTPInputStreamCommon(MemoryManager *manager)
00046       : fBytesProcessed(0)
00047       , fBuffer(1023, manager)
00048       , fContentType(0)
00049       , fMemoryManager(manager)
00050 {
00051 }
00052 
00053 
00054 BinHTTPInputStreamCommon::~BinHTTPInputStreamCommon()
00055 {
00056     if(fContentType) fMemoryManager->deallocate(fContentType);
00057 }
00058 
00059 static const char *CRLF = "\r\n";
00060 
00061 void BinHTTPInputStreamCommon::createHTTPRequest(const XMLURL &urlSource, const XMLNetHTTPInfo *httpInfo, CharBuffer &buffer)
00062 {
00063     static const char *GET = "GET ";
00064     static const char *PUT = "PUT ";
00065     static const char *POST = "POST ";
00066     static const char *HTTP10 = " HTTP/1.0\r\n";
00067     static const char *HOST = "Host: ";
00068     static const char *AUTHORIZATION = "Authorization: Basic ";
00069     static const char *COLON = ":";
00070 
00071     XMLTransService::Codes failReason;
00072     const XMLSize_t blockSize = 2048;
00073 
00074     XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor("ISO8859-1", failReason, blockSize, fMemoryManager);
00075     Janitor<XMLTranscoder> janTrans(trans);
00076 
00077     TranscodeToStr hostName(urlSource.getHost(), trans, fMemoryManager);
00078     TranscodeToStr path(urlSource.getPath(), trans, fMemoryManager);
00079     TranscodeToStr fragment(urlSource.getFragment(), trans, fMemoryManager);
00080     TranscodeToStr query(urlSource.getQuery(), trans, fMemoryManager);
00081 
00082     // Build up the http GET command to send to the server.
00083     // To do:  We should really support http 1.1.  This implementation
00084     //         is weak.
00085     if(httpInfo) {
00086         switch(httpInfo->fHTTPMethod) {
00087         case XMLNetHTTPInfo::GET:   buffer.append(GET); break;
00088         case XMLNetHTTPInfo::PUT:   buffer.append(PUT); break;
00089         case XMLNetHTTPInfo::POST:  buffer.append(POST); break;
00090         }
00091     }
00092     else {
00093         buffer.append(GET);
00094     }
00095 
00096     if(path.str() != 0) {
00097         buffer.append((char*)path.str());
00098     }
00099     else {
00100         buffer.append("/");
00101     }
00102 
00103     if(query.str() != 0) {
00104         buffer.append("?");
00105         buffer.append((char*)query.str());
00106     }
00107 
00108     if(fragment.str() != 0) {
00109         buffer.append((char*)fragment.str());
00110     }
00111     buffer.append(HTTP10);
00112 
00113     buffer.append(HOST);
00114     buffer.append((char*)hostName.str());
00115     if(urlSource.getPortNum() != 80)
00116     {
00117         buffer.append(COLON);
00118         buffer.appendDecimalNumber(urlSource.getPortNum());
00119     }
00120     buffer.append(CRLF);
00121 
00122     const XMLCh *username = urlSource.getUser();
00123     const XMLCh *password = urlSource.getPassword();
00124     if(username && password) {
00125         XMLBuffer userPassBuf(256, fMemoryManager);
00126         userPassBuf.append(username);
00127         userPassBuf.append(chColon);
00128         userPassBuf.append(password);
00129 
00130         TranscodeToStr userPass(userPassBuf.getRawBuffer(), trans, fMemoryManager);
00131 
00132         XMLSize_t len;
00133         XMLByte* encodedData = Base64::encode(userPass.str(), userPass.length(), &len, fMemoryManager);
00134         ArrayJanitor<XMLByte> janBuf2(encodedData, fMemoryManager);
00135 
00136         if(encodedData) {
00137             // HTTP doesn't want the 0x0A separating the data in chunks of 76 chars per line
00138             XMLByte* authData = (XMLByte*)fMemoryManager->allocate((len+1)*sizeof(XMLByte));
00139             ArrayJanitor<XMLByte> janBuf(authData, fMemoryManager);
00140             XMLByte *cursor = authData;
00141             for(XMLSize_t i = 0; i < len; ++i)
00142                 if(encodedData[i] != chLF)
00143                     *cursor++ = encodedData[i];
00144             *cursor++ = 0;
00145             buffer.append(AUTHORIZATION);
00146             buffer.append((char*)authData);
00147             buffer.append(CRLF);
00148         }
00149     }
00150 
00151     if(httpInfo && httpInfo->fHeaders)
00152         buffer.append(httpInfo->fHeaders, httpInfo->fHeadersLen);
00153 
00154     buffer.append(CRLF);
00155 }
00156 
00157 XMLCh *BinHTTPInputStreamCommon::findHeader(const char *name)
00158 {
00159     XMLSize_t len = strlen(name);
00160 
00161     char *p = strstr(fBuffer.getRawBuffer(), name);
00162     while(p != 0) {
00163         if(*(p - 1) == '\n' &&
00164             *(p + len) == ':' &&
00165             *(p + len + 1) == ' ') {
00166 
00167             p += len + 2;
00168 
00169             char *endP = strstr(p, CRLF);
00170             if(endP == 0) {
00171                 for(endP = p; *endP != 0; ++endP) ;
00172             }
00173 
00174             // Transcode from iso-8859-1
00175             TranscodeFromStr value((XMLByte*)p, endP - p, "ISO8859-1", fMemoryManager);
00176             return value.adopt();
00177         }
00178 
00179         p = strstr(p + 1, name);
00180     }
00181 
00182     return 0;
00183 }
00184 
00185 int BinHTTPInputStreamCommon::sendRequest(const XMLURL &url, const XMLNetHTTPInfo *httpInfo)
00186 {
00187     //
00188     //  Constants in ASCII to send/check in the HTTP request/response
00189     //
00190 
00191     static const char *CRLF2X = "\r\n\r\n";
00192     static const char *LF2X = "\n\n";
00193 
00194     // The port is open and ready to go.
00195     // Build up the http GET command to send to the server.
00196     CharBuffer requestBuffer(1023, fMemoryManager);
00197     createHTTPRequest(url, httpInfo, requestBuffer);
00198 
00199     // Send the http request
00200     if(!send(requestBuffer.getRawBuffer(), requestBuffer.getLen())) {
00201         ThrowXMLwithMemMgr1(NetAccessorException,
00202                             XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager);
00203     }
00204 
00205     if(httpInfo && httpInfo->fPayload) {
00206         if(!send(httpInfo->fPayload, httpInfo->fPayloadLen)) {
00207             ThrowXMLwithMemMgr1(NetAccessorException,
00208                                 XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager);
00209         }
00210     }
00211 
00212     //
00213     // get the response, check the http header for errors from the server.
00214     //
00215     char tmpBuf[1024];
00216     int ret;
00217 
00218     fBuffer.reset();
00219     while(true) {
00220         ret = receive(tmpBuf, sizeof(tmpBuf));
00221         if(ret == -1) {
00222             ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager);
00223         }
00224 
00225         fBuffer.append(tmpBuf, ret);
00226 
00227         fBufferPos = strstr(fBuffer.getRawBuffer(), CRLF2X);
00228         if(fBufferPos != 0) {
00229             fBufferPos += 4;
00230             *(fBufferPos - 2) = 0;
00231             break;
00232         }
00233 
00234         fBufferPos = strstr(fBuffer.getRawBuffer(), LF2X);
00235         if(fBufferPos != 0) {
00236             fBufferPos += 2;
00237             *(fBufferPos - 1) = 0;
00238             break;
00239         }
00240     }
00241 
00242     // Parse the response status
00243     char *p = strstr(fBuffer.getRawBuffer(), "HTTP");
00244     if(p == 0) {
00245         ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager);
00246     }
00247 
00248     p = strchr(p, chSpace);
00249     if(p == 0) {
00250         ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager);
00251     }
00252 
00253     return atoi(p);
00254 }
00255 
00256 const XMLCh *BinHTTPInputStreamCommon::getContentType() const
00257 {
00258     if(fContentType == 0) {
00259         // mutable
00260         const_cast<BinHTTPInputStreamCommon*>(this)->fContentType =
00261         const_cast<BinHTTPInputStreamCommon*>(this)->findHeader("Content-Type");
00262     }
00263     return fContentType;
00264 }
00265 
00266 XMLSize_t BinHTTPInputStreamCommon::readBytes(XMLByte* const    toFill,
00267                                               const XMLSize_t    maxToRead)
00268 {
00269     XMLSize_t len = fBuffer.getRawBuffer() + fBuffer.getLen() - fBufferPos;
00270     if(len > 0)
00271     {
00272         // If there's any data left over in the buffer into which we first
00273         //   read from the server (to get the http header), return that.
00274         if (len > maxToRead)
00275             len = maxToRead;
00276         memcpy(toFill, fBufferPos, len);
00277         fBufferPos += len;
00278     }
00279     else
00280     {
00281         // There was no data in the local buffer.
00282         // Read some from the socket, straight into our caller's buffer.
00283         //
00284         int cbRead = receive((char *)toFill, maxToRead);
00285         if (cbRead == -1)
00286         {
00287             ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, fMemoryManager);
00288         }
00289         len = cbRead;
00290     }
00291 
00292     fBytesProcessed += len;
00293     return len;
00294 }
00295 
00296 XERCES_CPP_NAMESPACE_END