diff -ru xerces-c-src_2_8_0-release/src/xercesc/util/BinInputStream.cpp xerces-c-src_2_8_0/src/xercesc/util/BinInputStream.cpp --- xerces-c-src_2_8_0-release/src/xercesc/util/BinInputStream.cpp 2008-02-08 15:30:17.000000000 +0000 +++ xerces-c-src_2_8_0/src/xercesc/util/BinInputStream.cpp 2008-01-28 02:24:47.000000000 +0000 @@ -42,4 +42,10 @@ { } +const XMLCh *BinInputStream::getContentType() const +{ + // The default implementation never returns a content type + return 0; +} + XERCES_CPP_NAMESPACE_END diff -ru xerces-c-src_2_8_0-release/src/xercesc/util/BinInputStream.hpp xerces-c-src_2_8_0/src/xercesc/util/BinInputStream.hpp --- xerces-c-src_2_8_0-release/src/xercesc/util/BinInputStream.hpp 2008-02-08 15:30:17.000000000 +0000 +++ xerces-c-src_2_8_0/src/xercesc/util/BinInputStream.hpp 2008-01-28 02:23:51.000000000 +0000 @@ -46,6 +46,7 @@ , const unsigned int maxToRead ) = 0; + virtual const XMLCh *getContentType() const; protected : // ----------------------------------------------------------------------- diff -ru xerces-c-src_2_8_0-release/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.cpp xerces-c-src_2_8_0/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.cpp --- xerces-c-src_2_8_0-release/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.cpp 2008-02-08 15:30:17.000000000 +0000 +++ xerces-c-src_2_8_0/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.cpp 2008-01-29 00:08:59.000000000 +0000 @@ -58,7 +58,14 @@ int* get() const { return fData; } int* release() { int* p = fData; fData = 0; return p; } - void reset(int* p = 0) { if(fData) close(*fData); fData=p; } + void reset(int* p = 0) + { + if(fData) { + shutdown(*fData, 2); + close(*fData); + } + fData = p; + } bool isDataNull() { return (fData == 0); } private : @@ -79,370 +86,372 @@ int* fData; }; -UnixHTTPURLInputStream::UnixHTTPURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/) - : fSocket(0) - , fBytesProcessed(0) - , fMemoryManager(urlSource.getMemoryManager()) +class TranscodeStr { +public: + TranscodeStr(const XMLCh *in, XMLTranscoder* trans, + MemoryManager *manager = XMLPlatformUtils::fgMemoryManager) + : fString(0), + fBytesWritten(0), + fMemoryManager(manager) + { + if(in) { + unsigned int len = XMLString::stringLen(in) + 1; + + unsigned int allocSize = len * sizeof(XMLCh); + fString = (unsigned char*)fMemoryManager->allocate(allocSize); + + unsigned int charsRead; + + unsigned int charsDone = 0; + + while(true) { + fBytesWritten += trans->transcodeTo(in + charsDone, len - charsDone, + fString + fBytesWritten, allocSize - fBytesWritten, + charsRead, XMLTranscoder::UnRep_Throw); + charsDone += charsRead; + + if(charsDone == len) break; + + allocSize *= 2; + unsigned char *newBuf = (unsigned char*)fMemoryManager->allocate(allocSize); + memcpy(newBuf, fString, fBytesWritten); + fMemoryManager->deallocate(fString); + fString = newBuf; + } + } + } - // - // Constants in ASCII to send/check in the HTTP request/response - // - - const char GET[] = - { - chLatin_G, chLatin_E, chLatin_T, chSpace, chNull - }; - - const char PUT[] = - { - chLatin_P, chLatin_U, chLatin_T, chSpace, chNull - }; - - const char POST[] = - { - chLatin_P, chLatin_O, chLatin_S, chLatin_T, chSpace, chNull - }; - - const char HTTP[] = - { - chLatin_H, chLatin_T, chLatin_T, chLatin_P, chNull - }; - - const char HTTP10[] = - { - chSpace, chLatin_H, chLatin_T, chLatin_T, chLatin_P, chForwardSlash, chDigit_1, chPeriod, chDigit_0, chCR, chLF, chNull - }; - - const char CRLF[] = - { - chCR, chLF, chNull - }; - - const char CRLF2X[] = + ~TranscodeStr() { - chCR, chLF, chCR, chLF, chNull - }; + if(fString) + fMemoryManager->deallocate(fString); + } - const char LF2X[] = + const unsigned char *str() const { - chLF, chLF, chNull - }; + return fString; + } - const char HOST[] = + unsigned int len() const { - chLatin_H, chLatin_o, chLatin_s, chLatin_t, chColon, chSpace, chNull - }; + return fBytesWritten; + } - const char COLON[] = - { - chColon, chNull - }; +private: + unsigned char *fString; + unsigned int fBytesWritten; + MemoryManager *fMemoryManager; +}; - const char AUTHORIZATION[] = - { - chLatin_A, chLatin_u, chLatin_t, chLatin_h, chLatin_o, chLatin_r, chLatin_i, chLatin_z, chLatin_a, chLatin_t, - chLatin_i, chLatin_o, chLatin_n, chColon, chSpace, chLatin_B, chLatin_a, chLatin_s, chLatin_i, chLatin_c, chSpace, chNull - }; +static const char *CRLF = "\r\n"; - const char resp200 [] = - { - chSpace, chDigit_2, chDigit_0, chDigit_0, chSpace, chNull - }; +void UnixHTTPURLInputStream::createHTTPRequest(const XMLURL &urlSource, const XMLNetHTTPInfo *httpInfo, CharBuffer &buffer) +{ + static const char *GET = "GET "; + static const char *PUT = "PUT "; + static const char *POST = "POST "; + static const char *HTTP10 = " HTTP/1.0\r\n"; + static const char *HOST = "Host: "; + static const char *AUTHORIZATION = "Authorization: Basic "; + static const char *COLON = ":"; - unsigned int charsEaten; - unsigned int transSize; XMLTransService::Codes failReason; const unsigned int blockSize = 2048; - const unsigned int bufSize = 5; - static XMLCh portBuffer[bufSize+1]; - - // - // Pull all of the parts of the URL out of the urlSource object - // - - const XMLCh* hostName = urlSource.getHost(); - const XMLCh* path = urlSource.getPath(); - const XMLCh* fragment = urlSource.getFragment(); - const XMLCh* query = urlSource.getQuery(); - // - // Convert the hostName to the platform's code page for gethostbyname and - // inet_addr functions. - // + XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor("ISO8859-1", failReason, blockSize, fMemoryManager); + Janitor<XMLTranscoder> janTrans(trans); - char* hostNameAsCharStar = XMLString::transcode(hostName, fMemoryManager); - ArrayJanitor<char> janBuf1(hostNameAsCharStar, fMemoryManager); + TranscodeStr hostName(urlSource.getHost(), trans, fMemoryManager); + TranscodeStr path(urlSource.getPath(), trans, fMemoryManager); + TranscodeStr fragment(urlSource.getFragment(), trans, fMemoryManager); + TranscodeStr query(urlSource.getQuery(), trans, fMemoryManager); - // - // Convert all the parts of the urlSource object to ASCII so they can be - // sent to the remote host in that format - // + // Build up the http GET command to send to the server. + // To do: We should really support http 1.1. This implementation + // is weak. + if(httpInfo) { + switch(httpInfo->fHTTPMethod) { + case XMLNetHTTPInfo::GET: buffer.append(GET); break; + case XMLNetHTTPInfo::PUT: buffer.append(PUT); break; + case XMLNetHTTPInfo::POST: buffer.append(POST); break; + } + } + else { + buffer.append(GET); + } - transSize = XMLString::stringLen(hostName)+1; - char* hostNameAsASCII = (char*) fMemoryManager->allocate - ( - (transSize+1) * sizeof(char) - );//new char[transSize+1]; - ArrayJanitor<char> janBuf2(hostNameAsASCII, fMemoryManager); + if(path.str() != 0) { + buffer.append((char*)path.str()); + } + else { + buffer.append("/"); + } - XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor("ISO8859-1", failReason, blockSize, fMemoryManager); - trans->transcodeTo(hostName, transSize, (unsigned char *) hostNameAsASCII, transSize, charsEaten, XMLTranscoder::UnRep_Throw); + if(query.str() != 0) { + buffer.append("?"); + buffer.append((char*)query.str()); + } - char* pathAsASCII = 0; - ArrayJanitor<char> janBuf3(pathAsASCII, fMemoryManager); - if (path) - { - transSize = XMLString::stringLen(path)+1; - pathAsASCII = (char*) fMemoryManager->allocate - ( - (transSize+1) * sizeof(char) - );//new char[transSize+1]; - janBuf3.reset(pathAsASCII, fMemoryManager); - trans->transcodeTo(path, transSize, (unsigned char *) pathAsASCII, transSize, charsEaten, XMLTranscoder::UnRep_Throw); + if(fragment.str() != 0) { + buffer.append((char*)fragment.str()); } + buffer.append(HTTP10); - char* fragmentAsASCII = 0; - ArrayJanitor<char> janBuf4(fragmentAsASCII, fMemoryManager); - if (fragment) + buffer.append(HOST); + buffer.append((char*)hostName.str()); + if(urlSource.getPortNum() != 80) { - transSize = XMLString::stringLen(fragment)+1; - fragmentAsASCII = (char*) fMemoryManager->allocate - ( - (transSize+1) * sizeof(char) - );//new char[transSize+1]; - janBuf4.reset(fragmentAsASCII, fMemoryManager); - trans->transcodeTo(fragment, transSize, (unsigned char *) fragmentAsASCII, transSize, charsEaten, XMLTranscoder::UnRep_Throw); + buffer.append(COLON); + buffer.appendDecimalNumber(urlSource.getPortNum()); } + buffer.append(CRLF); - char* queryAsASCII = 0; - ArrayJanitor<char> janBuf5(queryAsASCII, fMemoryManager); - if (query) - { - transSize = XMLString::stringLen(query)+1; - queryAsASCII = (char*) fMemoryManager->allocate - ( - (transSize+1) * sizeof(char) - );//new char[transSize+1]; - janBuf5.reset(queryAsASCII, fMemoryManager); - trans->transcodeTo(query, transSize, (unsigned char *) queryAsASCII, transSize, charsEaten, XMLTranscoder::UnRep_Throw); + const XMLCh *username = urlSource.getUser(); + const XMLCh *password = urlSource.getPassword(); + if(username && password) { + XMLBuffer userPassBuf(256, fMemoryManager); + userPassBuf.append(username); + userPassBuf.append(chColon); + userPassBuf.append(password); + + TranscodeStr userPass(userPassBuf.getRawBuffer(), trans, fMemoryManager); + + unsigned int len; + XMLByte* encodedData = Base64::encode((XMLByte*)userPass.str(), userPass.len() - 1, &len, fMemoryManager); + ArrayJanitor<XMLByte> janBuf2(encodedData, fMemoryManager); + + if(encodedData) { + // HTTP doesn't want the 0x0A separating the data in chunks of 76 chars per line + XMLByte* authData = (XMLByte*)fMemoryManager->allocate((len+1)*sizeof(XMLByte)); + ArrayJanitor<XMLByte> janBuf(authData, fMemoryManager); + XMLByte *cursor = authData; + for(unsigned int i = 0; i < len; ++i) + if(encodedData[i] != chLF) + *cursor++ = encodedData[i]; + *cursor++ = 0; + buffer.append(AUTHORIZATION); + buffer.append((char*)authData); + buffer.append(CRLF); + } } - unsigned short portNumber = (unsigned short) urlSource.getPortNum(); + if(httpInfo && httpInfo->fHeaders) + buffer.append(httpInfo->fHeaders, httpInfo->fHeadersLen); - // - // Convert port number integer to unicode so we can transcode it to ASCII - // + buffer.append(CRLF); +} - XMLString::binToText((unsigned int) portNumber, portBuffer, bufSize, 10, fMemoryManager); - transSize = XMLString::stringLen(portBuffer)+1; - char* portAsASCII = (char*) fMemoryManager->allocate - ( - (transSize+1) * sizeof(char) - );//new char[transSize+1]; - ArrayJanitor<char> janBuf6(portAsASCII, fMemoryManager); - trans->transcodeTo(portBuffer, transSize, (unsigned char *) portAsASCII, transSize, charsEaten, XMLTranscoder::UnRep_Throw); +int UnixHTTPURLInputStream::parseResponseStatus() const +{ + char *p = const_cast<char*>(strstr(fBuffer.getRawBuffer(), "HTTP")); + if(p == 0) return -1; - delete trans; + p = strchr(p, chSpace); + if(p == 0) return -1; + + return atoi(p); +} - // - // Set up a socket. - // - struct hostent* hostEntPtr = 0; - struct sockaddr_in sa; +XMLCh *UnixHTTPURLInputStream::findHeader(const char *name) const +{ + int len = strlen(name); - // Use the hostName in the local code page .... - if ((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL) - { - unsigned long numAddress = inet_addr(hostNameAsCharStar); - if (numAddress < 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_TargetResolution, hostName, fMemoryManager); + char *p = const_cast<char*>(strstr(fBuffer.getRawBuffer(), name)); + while(p != 0) { + if(*(p - 1) == '\n' && + *(p + len) == ':' && + *(p + len + 1) == ' ') { + + p += len + 2; + + char *endP = strstr(p, CRLF); + if(endP == 0) { + for(endP = p; *endP != 0; ++endP); + } + + char tmp = *endP; + *endP = 0; + + XMLCh *value = XMLString::transcode(p, fMemoryManager); + *endP = tmp; + return value; } - if ((hostEntPtr = - gethostbyaddr((char *) &numAddress, - sizeof(unsigned long), AF_INET)) == NULL) - { - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_TargetResolution, hostName, fMemoryManager); - } - } - - memset(&sa, '\0', sizeof(sockaddr_in)); // iSeries fix ?? - memcpy((void *) &sa.sin_addr, - (const void *) hostEntPtr->h_addr, hostEntPtr->h_length); - sa.sin_family = hostEntPtr->h_addrtype; - sa.sin_port = htons(portNumber); - int s = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0); - if (s < 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_CreateSocket, urlSource.getURLText(), fMemoryManager); + p = strstr(p + 1, name); } - SocketJanitor janSock(&s); - if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_ConnSocket, urlSource.getURLText(), fMemoryManager); - } + return 0; +} - // The port is open and ready to go. - // Build up the http GET command to send to the server. - // To do: We should really support http 1.1. This implementation - // is weak. - if(httpInfo==0) - strcpy(fBuffer, GET); - else - switch(httpInfo->fHTTPMethod) - { - case XMLNetHTTPInfo::GET: strcpy(fBuffer, GET); break; - case XMLNetHTTPInfo::PUT: strcpy(fBuffer, PUT); break; - case XMLNetHTTPInfo::POST: strcpy(fBuffer, POST); break; - } - if (pathAsASCII != 0) - { - strcat(fBuffer, pathAsASCII); - } +bool UnixHTTPURLInputStream::send(const char *buf, unsigned int len) +{ + unsigned int done = 0; + int ret; - if (queryAsASCII != 0) - { - size_t n = strlen(fBuffer); - fBuffer[n] = chQuestion; - fBuffer[n+1] = chNull; - strcat(fBuffer, queryAsASCII); + while(done < len) { + ret = ::send(fSocket, buf + done, len - done, 0); + if(ret == -1) return false; + done += ret; } - if (fragmentAsASCII != 0) - { - strcat(fBuffer, fragmentAsASCII); - } - strcat(fBuffer, HTTP10); + return true; +} - strcat(fBuffer, HOST); - strcat(fBuffer, hostNameAsASCII); - if (portNumber != 80) - { - strcat(fBuffer,COLON); - strcat(fBuffer,portAsASCII); - } - strcat(fBuffer, CRLF); +UnixHTTPURLInputStream::UnixHTTPURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/) + : fSocket(0) + , fBytesProcessed(0) + , fBuffer(1023, urlSource.getMemoryManager()) + , fContentType(0) + , fMemoryManager(urlSource.getMemoryManager()) +{ + // + // Constants in ASCII to send/check in the HTTP request/response + // - const XMLCh* username = urlSource.getUser(); - const XMLCh* password = urlSource.getPassword(); - if (username && password) - { - XMLBuffer userPass(256, fMemoryManager); - userPass.append(username); - userPass.append(chColon); - userPass.append(password); - char* userPassAsCharStar = XMLString::transcode(userPass.getRawBuffer(), fMemoryManager); - ArrayJanitor<char> janBuf(userPassAsCharStar, fMemoryManager); + static const char *CRLF2X = "\r\n\r\n"; + static const char *LF2X = "\n\n"; - unsigned int len; - XMLByte* encodedData = Base64::encode((XMLByte *)userPassAsCharStar, strlen(userPassAsCharStar), &len, fMemoryManager); - ArrayJanitor<XMLByte> janBuf2(encodedData, fMemoryManager); + // + // Convert the hostName to the platform's code page for gethostbyname and + // inet_addr functions. + // - if (encodedData) - { - // HTTP doesn't want the 0x0A separating the data in chunks of 76 chars per line - XMLByte* authData = (XMLByte*)fMemoryManager->allocate((len+1)*sizeof(XMLByte)); - ArrayJanitor<XMLByte> janBuf(authData, fMemoryManager); - XMLByte* cursor=authData; - for(unsigned int i=0;i<len;i++) - if(encodedData[i]!=chLF) - *cursor++=encodedData[i]; - *cursor++=0; - strcat(fBuffer, AUTHORIZATION); - strcat(fBuffer, (char*)authData); - strcat(fBuffer, CRLF); - } - } + const XMLCh* hostName = urlSource.getHost(); + char* hostNameAsCharStar = XMLString::transcode(hostName, fMemoryManager); + ArrayJanitor<char> janHostNameAsCharStar(hostNameAsCharStar, fMemoryManager); - if(httpInfo!=0 && httpInfo->fHeaders!=0) - strncat(fBuffer,httpInfo->fHeaders,httpInfo->fHeadersLen); + XMLURL url(urlSource); + int redirectCount = 0; + SocketJanitor janSock(0); + + do { + // + // Set up a socket. + // - strcat(fBuffer, CRLF); + struct hostent *hostEntPtr = 0; + struct sockaddr_in sa; - // Send the http request - int lent = strlen(fBuffer); - int aLent = 0; + // Use the hostName in the local code page .... + if((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL) + { + unsigned long numAddress = inet_addr(hostNameAsCharStar); + if ((hostEntPtr = + gethostbyaddr((char *) &numAddress, + sizeof(unsigned long), AF_INET)) == NULL) + { + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_TargetResolution, hostName, fMemoryManager); + } + } - if ((aLent = write(s, (void *) fBuffer, lent)) != lent) - { - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_WriteSocket, urlSource.getURLText(), fMemoryManager); - } + memset(&sa, '\0', sizeof(sockaddr_in)); // iSeries fix ?? + memcpy((void *) &sa.sin_addr, + (const void *) hostEntPtr->h_addr, hostEntPtr->h_length); + sa.sin_family = hostEntPtr->h_addrtype; + sa.sin_port = htons((unsigned short)url.getPortNum()); + + janSock.reset(); + fSocket = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0); + if(fSocket < 0) + { + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_CreateSocket, url.getURLText(), fMemoryManager); + } + janSock.reset(&fSocket); - if(httpInfo!=0 && httpInfo->fPayload!=0) { - int aLent = 0; - if ((aLent = write(s, (void *) httpInfo->fPayload, httpInfo->fPayloadLen)) != httpInfo->fPayloadLen) + if(connect(fSocket, (struct sockaddr *) &sa, sizeof(sa)) < 0) { ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_WriteSocket, urlSource.getURLText(), fMemoryManager); + XMLExcepts::NetAcc_ConnSocket, url.getURLText(), fMemoryManager); } - } - // - // get the response, check the http header for errors from the server. - // - aLent = read(s, (void *)fBuffer, sizeof(fBuffer)-1); - if (aLent <= 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText(), fMemoryManager); - } - fBufferEnd = fBuffer+aLent; - *fBufferEnd = 0; + // The port is open and ready to go. + // Build up the http GET command to send to the server. + CharBuffer requestBuffer(1023, fMemoryManager); + createHTTPRequest(url, httpInfo, requestBuffer); - // Find the break between the returned http header and any data. - // (Delimited by a blank line) - // Hang on to any data for use by the first read from this BinHTTPURLInputStream. - // - fBufferPos = strstr(fBuffer, CRLF2X); - if (fBufferPos != 0) - { - fBufferPos += 4; - *(fBufferPos-2) = 0; - } - else - { - fBufferPos = strstr(fBuffer, LF2X); - if (fBufferPos != 0) - { - fBufferPos += 2; - *(fBufferPos-1) = 0; + // Send the http request + if(!send(requestBuffer.getRawBuffer(), requestBuffer.getLen())) { + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager); } - else - fBufferPos = fBufferEnd; - } - // Make sure the header includes an HTTP 200 OK response. - // - char *p = strstr(fBuffer, HTTP); - if (p == 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText(), fMemoryManager); - } + if(httpInfo && httpInfo->fPayload) { + if(!send(httpInfo->fPayload, httpInfo->fPayloadLen)) { + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager); + } + } - p = strchr(p, chSpace); - if (p == 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText(), fMemoryManager); - } - - if (memcmp(p, resp200, strlen(resp200))) - { - // Most likely a 404 Not Found error. - // Should recognize and handle the forwarding responses. // - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, urlSource.getURLText(), fMemoryManager); - } + // get the response, check the http header for errors from the server. + // + char tmpBuf[1024]; + int ret; + + fBuffer.reset(); + while(true) { + ret = ::recv(fSocket, tmpBuf, sizeof(tmpBuf), 0); + if(ret == -1) { + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager); + } + + fBuffer.append(tmpBuf, ret); + + fBufferPos = strstr(fBuffer.getRawBuffer(), CRLF2X); + if(fBufferPos != 0) { + fBufferPos += 4; + *(fBufferPos - 2) = 0; + break; + } + + fBufferPos = strstr(fBuffer.getRawBuffer(), LF2X); + if(fBufferPos != 0) { + fBufferPos += 2; + *(fBufferPos - 1) = 0; + break; + } + } + + int status = parseResponseStatus(); + if(status < 0) { + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager); + } - fSocket = *janSock.release(); + if(status == 200) { + // HTTP 200 OK response means we're done. + // We're done + break; + } + // a 3xx response means there was an HTTP redirect + else if(status >= 300 && status <= 307) { + redirectCount++; + + XMLCh *newURLString = findHeader("Location"); + ArrayJanitor<XMLCh> janNewURLString(newURLString, fMemoryManager); + + XMLURL newURL(fMemoryManager); + newURL.setURL(url, newURLString); + if(newURL.getProtocol() != XMLURL::HTTP) { + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, newURL.getURLText(), fMemoryManager); + } + + url = newURL; + + janHostNameAsCharStar.release(); + hostNameAsCharStar = XMLString::transcode(newURL.getHost(), fMemoryManager); + janHostNameAsCharStar.reset(hostNameAsCharStar, fMemoryManager); + } + else { + // Most likely a 404 Not Found error. + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), fMemoryManager); + } + } while(redirectCount < 6); + janSock.release(); } @@ -450,14 +459,24 @@ { shutdown(fSocket, 2); close(fSocket); + + if(fContentType) fMemoryManager->deallocate(fContentType); } +const XMLCh *UnixHTTPURLInputStream::getContentType() const +{ + if(fContentType == 0) { + // mutable + const_cast<XMLCh*&>(fContentType) = findHeader("Content-Type"); + } + return fContentType; +} unsigned int UnixHTTPURLInputStream::readBytes(XMLByte* const toFill , const unsigned int maxToRead) { - unsigned int len = fBufferEnd - fBufferPos; - if (len > 0) + unsigned int len = fBuffer.getRawBuffer() + fBuffer.getLen() - fBufferPos; + if(len > 0) { // If there's any data left over in the buffer into which we first // read from the server (to get the http header), return that. @@ -472,7 +491,7 @@ // Read some from the socket, straight into our caller's buffer. // len = read(fSocket, (void *) toFill, maxToRead); - if (len == -1) + if (len == (unsigned int)-1) { ThrowXMLwithMemMgr(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, fMemoryManager); } diff -ru xerces-c-src_2_8_0-release/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp xerces-c-src_2_8_0/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp --- xerces-c-src_2_8_0-release/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp 2008-02-08 15:30:17.000000000 +0000 +++ xerces-c-src_2_8_0/src/xercesc/util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp 2008-01-28 23:49:33.000000000 +0000 @@ -27,10 +27,132 @@ #include <xercesc/util/XMLExceptMsgs.hpp> #include <xercesc/util/BinInputStream.hpp> #include <xercesc/util/XMLNetAccessor.hpp> +#include <xercesc/framework/MemoryManager.hpp> XERCES_CPP_NAMESPACE_BEGIN // +// This class implements a simple expanding character buffer +// +class XMLUTIL_EXPORT CharBuffer +{ +public: + CharBuffer(unsigned int capacity = 1023, + MemoryManager *manager = XMLPlatformUtils::fgMemoryManager) + : fCapacity(capacity), + fIndex(0), + fMemoryManager(manager) + { + fBuffer = (char*)fMemoryManager->allocate((fCapacity + 1) * sizeof(char)); + } + + ~CharBuffer() + { + fMemoryManager->deallocate(fBuffer); + } + + const char* getRawBuffer() const + { + fBuffer[fIndex] = 0; + return fBuffer; + } + + char* getRawBuffer() + { + fBuffer[fIndex] = 0; + return fBuffer; + } + + unsigned int getLen() const + { + return fIndex; + } + + void reset() + { + fIndex = 0; + } + + void append(const char *chars) + { + if(chars != 0 && *chars != 0) { + // get length of chars + unsigned int count = 0; + for(; *(chars+count); ++count); + + if(fIndex + count >= fCapacity) { + insureCapacity(count); + } + memcpy(&fBuffer[fIndex], chars, count * sizeof(char)); + fIndex += count; + } + } + + void append(const char *chars, unsigned int len) + { + if(chars != 0 && len != 0) { + if(fIndex + len >= fCapacity) { + insureCapacity(len); + } + memcpy(&fBuffer[fIndex], chars, len * sizeof(char)); + fIndex += len; + } + } + + void appendDecimalNumber(unsigned int n) + { + if(n >= 10) appendDecimalNumber(n / 10); + + if(fIndex + 1 >= fCapacity) + insureCapacity(1); + + fBuffer[fIndex] = '0' + n; + ++fIndex; + } + + void set(const char *chars) + { + reset(); + append(chars); + } + +private: + // ----------------------------------------------------------------------- + // Unimplemented constructors and operators + // ----------------------------------------------------------------------- + CharBuffer(const CharBuffer &); + CharBuffer &operator=(const CharBuffer &); + + void insureCapacity(unsigned int extraNeeded) + { + // If we can't handle it, try doubling the buffer size. + unsigned int newCap = (fIndex + extraNeeded) * 2; + + if(newCap > fCapacity) + { + // Allocate new buffer + char* newBuf = (char*)fMemoryManager->allocate((newCap + 1) * sizeof(char)); + + // Copy over the old stuff + memcpy(newBuf, fBuffer, fIndex * sizeof(char)); + + // Clean up old buffer and store new stuff + fMemoryManager->deallocate(fBuffer); + fBuffer = newBuf; + fCapacity = newCap; + } + } + + // ----------------------------------------------------------------------- + // Private data members + // ----------------------------------------------------------------------- + char *fBuffer; + unsigned int fCapacity; + unsigned int fIndex; + MemoryManager *fMemoryManager; +}; + +// // This class implements the BinInputStream interface specified by the XML // parser. // @@ -48,6 +170,7 @@ , const unsigned int maxToRead ); + const XMLCh *getContentType() const; private : // ----------------------------------------------------------------------- @@ -56,6 +179,11 @@ UnixHTTPURLInputStream(const UnixHTTPURLInputStream&); UnixHTTPURLInputStream& operator=(const UnixHTTPURLInputStream&); + void createHTTPRequest(const XMLURL &urlSource, const XMLNetHTTPInfo *httpInfo, CharBuffer &buffer); + int parseResponseStatus() const; + XMLCh *findHeader(const char *name) const; + bool send(const char *buf, unsigned int len); + // ----------------------------------------------------------------------- // Private data members // @@ -68,16 +196,16 @@ // Holds the http header, plus the first part of the actual // data. Filled at the time the stream is opened, data goes // out to user in response to readBytes(). - // fBufferPos, fBufferEnd + // fBufferPos // Pointers into fBuffer, showing start and end+1 of content // that readBytes must return. // ----------------------------------------------------------------------- int fSocket; unsigned int fBytesProcessed; - char fBuffer[4000]; - char * fBufferEnd; + CharBuffer fBuffer; char * fBufferPos; + XMLCh * fContentType; MemoryManager* fMemoryManager; }; // UnixHTTPURLInputStream --- xerces-c-src_2_8_0-release/src/xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.cpp 2007-08-28 14:44:16.000000000 -0400 +++ xerces-c-src_2_8_0/src/xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.cpp 2008-02-11 15:03:57.000000000 -0500 @@ -20,9 +20,6 @@ */ -#define INCL_WINSOCK_API_TYPEDEFS 1 -#include <winsock2.h> -#include <windows.h> #include <tchar.h> #include <stdio.h> @@ -37,6 +34,7 @@ #include <xercesc/util/Janitor.hpp> #include <xercesc/util/XMLUniDefs.hpp> #include <xercesc/util/Base64.hpp> +#include <xercesc/util/TransService.hpp> XERCES_CPP_NAMESPACE_BEGIN @@ -52,7 +50,14 @@ SOCKET* get() const { return fData; } SOCKET* release() { SOCKET* p = fData; fData = 0; return p; } - void reset(SOCKET* p = 0) { if(fData) BinHTTPURLInputStream::closesocket(*fData); fData=p; } + void reset(SOCKET* p = 0) + { + if(fData) { + BinHTTPURLInputStream::shutdown(*fData, SD_BOTH); + BinHTTPURLInputStream::closesocket(*fData); + } + fData = p; + } bool isDataNull() { return (fData == 0); } private : @@ -73,6 +78,218 @@ SOCKET* fData; }; +class TranscodeStr +{ +public: + TranscodeStr(const XMLCh *in, XMLTranscoder* trans, + MemoryManager *manager = XMLPlatformUtils::fgMemoryManager) + : fString(0), + fBytesWritten(0), + fMemoryManager(manager) + { + if(in) { + unsigned int len = XMLString::stringLen(in) + 1; + + unsigned int allocSize = len * sizeof(XMLCh); + fString = (unsigned char*)fMemoryManager->allocate(allocSize); + + unsigned int charsRead; + + unsigned int charsDone = 0; + + while(true) { + fBytesWritten += trans->transcodeTo(in + charsDone, len - charsDone, + fString + fBytesWritten, allocSize - fBytesWritten, + charsRead, XMLTranscoder::UnRep_Throw); + charsDone += charsRead; + + if(charsDone == len) break; + + allocSize *= 2; + unsigned char *newBuf = (unsigned char*)fMemoryManager->allocate(allocSize); + memcpy(newBuf, fString, fBytesWritten); + fMemoryManager->deallocate(fString); + fString = newBuf; + } + } + } + + ~TranscodeStr() + { + if(fString) + fMemoryManager->deallocate(fString); + } + + const unsigned char *str() const + { + return fString; + } + + unsigned int len() const + { + return fBytesWritten; + } + +private: + unsigned char *fString; + unsigned int fBytesWritten; + MemoryManager *fMemoryManager; +}; + +static const char *CRLF = "\r\n"; + +void BinHTTPURLInputStream::createHTTPRequest(const XMLURL &urlSource, const XMLNetHTTPInfo *httpInfo, CharBuffer &buffer) +{ + static const char *GET = "GET "; + static const char *PUT = "PUT "; + static const char *POST = "POST "; + static const char *HTTP10 = " HTTP/1.0\r\n"; + static const char *HOST = "Host: "; + static const char *AUTHORIZATION = "Authorization: Basic "; + static const char *COLON = ":"; + + XMLTransService::Codes failReason; + const unsigned int blockSize = 2048; + + XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor("ISO8859-1", failReason, blockSize, fMemoryManager); + Janitor<XMLTranscoder> janTrans(trans); + + TranscodeStr hostName(urlSource.getHost(), trans, fMemoryManager); + TranscodeStr path(urlSource.getPath(), trans, fMemoryManager); + TranscodeStr fragment(urlSource.getFragment(), trans, fMemoryManager); + TranscodeStr query(urlSource.getQuery(), trans, fMemoryManager); + + // Build up the http GET command to send to the server. + // To do: We should really support http 1.1. This implementation + // is weak. + if(httpInfo) { + switch(httpInfo->fHTTPMethod) { + case XMLNetHTTPInfo::GET: buffer.append(GET); break; + case XMLNetHTTPInfo::PUT: buffer.append(PUT); break; + case XMLNetHTTPInfo::POST: buffer.append(POST); break; + } + } + else { + buffer.append(GET); + } + + if(path.str() != 0) { + buffer.append((char*)path.str()); + } + else { + buffer.append("/"); + } + + if(query.str() != 0) { + buffer.append("?"); + buffer.append((char*)query.str()); + } + + if(fragment.str() != 0) { + buffer.append((char*)fragment.str()); + } + buffer.append(HTTP10); + + buffer.append(HOST); + buffer.append((char*)hostName.str()); + if(urlSource.getPortNum() != 80) + { + buffer.append(COLON); + buffer.appendDecimalNumber(urlSource.getPortNum()); + } + buffer.append(CRLF); + + const XMLCh *username = urlSource.getUser(); + const XMLCh *password = urlSource.getPassword(); + if(username && password) { + XMLBuffer userPassBuf(256, fMemoryManager); + userPassBuf.append(username); + userPassBuf.append(chColon); + userPassBuf.append(password); + + TranscodeStr userPass(userPassBuf.getRawBuffer(), trans, fMemoryManager); + + unsigned int len; + XMLByte* encodedData = Base64::encode((XMLByte*)userPass.str(), userPass.len() - 1, &len, fMemoryManager); + ArrayJanitor<XMLByte> janBuf2(encodedData, fMemoryManager); + + if(encodedData) { + // HTTP doesn't want the 0x0A separating the data in chunks of 76 chars per line + XMLByte* authData = (XMLByte*)fMemoryManager->allocate((len+1)*sizeof(XMLByte)); + ArrayJanitor<XMLByte> janBuf(authData, fMemoryManager); + XMLByte *cursor = authData; + for(unsigned int i = 0; i < len; ++i) + if(encodedData[i] != chLF) + *cursor++ = encodedData[i]; + *cursor++ = 0; + buffer.append(AUTHORIZATION); + buffer.append((char*)authData); + buffer.append(CRLF); + } + } + + if(httpInfo && httpInfo->fHeaders) + buffer.append(httpInfo->fHeaders, httpInfo->fHeadersLen); + + buffer.append(CRLF); +} + +int BinHTTPURLInputStream::parseResponseStatus() const +{ + char *p = strstr(const_cast<char*>(fBuffer.getRawBuffer()), "HTTP"); + if(p == 0) return -1; + + p = strchr(p, chSpace); + if(p == 0) return -1; + + return atoi(p); +} + +XMLCh *BinHTTPURLInputStream::findHeader(const char *name) const +{ + int len = strlen(name); + + char *p = strstr(const_cast<char*>(fBuffer.getRawBuffer()), name); + while(p != 0) { + if(*(p - 1) == '\n' && + *(p + len) == ':' && + *(p + len + 1) == ' ') { + + p += len + 2; + + char *endP = strstr(p, CRLF); + if(endP == 0) { + for(endP = p; *endP != 0; ++endP); + } + + char tmp = *endP; + *endP = 0; + + XMLCh *value = XMLString::transcode(p, fMemoryManager); + *endP = tmp; + return value; + } + + p = strstr(p + 1, name); + } + + return 0; +} + +bool BinHTTPURLInputStream::send(const char *buf, unsigned int len) +{ + unsigned int done = 0; + int ret; + + while(done < len) { + ret = send(fSocketHandle, buf + done, len - done, 0); + if(ret == SOCKET_ERROR) return false; + done += ret; + } + + return true; +} + static HMODULE gWinsockLib = NULL; static LPFN_GETHOSTBYNAME gWSgethostbyname = NULL; static LPFN_INET_ADDR gWSinet_addr = NULL; @@ -190,40 +407,43 @@ return (*gWShtons)(hostshort); } -unsigned int BinHTTPURLInputStream::socket(int af,int type,int protocol) +SOCKET BinHTTPURLInputStream::socket(int af,int type,int protocol) { return (*gWSsocket)(af,type,protocol); } -int BinHTTPURLInputStream::connect(unsigned int s,const sockaddr* name,int namelen) +int BinHTTPURLInputStream::connect(SOCKET s,const sockaddr* name,int namelen) { return (*gWSconnect)(s,name,namelen); } -int BinHTTPURLInputStream::send(unsigned int s,const char* buf,int len,int flags) +int BinHTTPURLInputStream::send(SOCKET s,const char* buf,int len,int flags) { return (*gWSsend)(s,buf,len,flags); } -int BinHTTPURLInputStream::recv(unsigned int s,char* buf,int len,int flags) +int BinHTTPURLInputStream::recv(SOCKET s,char* buf,int len,int flags) { return (*gWSrecv)(s,buf,len,flags); } -int BinHTTPURLInputStream::shutdown(unsigned int s,int how) +int BinHTTPURLInputStream::shutdown(SOCKET s,int how) { return (*gWSshutdown)(s,how); } -int BinHTTPURLInputStream::closesocket(unsigned int socket) +int BinHTTPURLInputStream::closesocket(SOCKET socket) { return (*gWSclosesocket)(socket); } BinHTTPURLInputStream::BinHTTPURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo /*=0*/) - : fSocketHandle(0) + : fMemoryManager(urlSource.getMemoryManager()) + , fSocketHandle(0) , fBytesProcessed(0) + , fBuffer(1023, urlSource.getMemoryManager()) + , fContentType(0) { if(!fInitialized) { @@ -243,257 +463,160 @@ } } - fMemoryManager = urlSource.getMemoryManager(); + // + // Constants in ASCII to send/check in the HTTP request/response + // + + static const char *CRLF2X = "\r\n\r\n"; + static const char *LF2X = "\n\n"; + // // Pull all of the parts of the URL out of th urlSource object, and transcode them // and transcode them back to ASCII. // const XMLCh* hostName = urlSource.getHost(); - char* hostNameAsCharStar = XMLString::transcode(hostName, urlSource.getMemoryManager()); - ArrayJanitor<char> janBuf1(hostNameAsCharStar, urlSource.getMemoryManager()); + char* hostNameAsCharStar = XMLString::transcode(hostName, fMemoryManager); + ArrayJanitor<char> janHostNameAsCharStar(hostNameAsCharStar, fMemoryManager); - const XMLCh* path = urlSource.getPath(); - char* pathAsCharStar = XMLString::transcode(path, urlSource.getMemoryManager()); - ArrayJanitor<char> janBuf2(pathAsCharStar, urlSource.getMemoryManager()); - - const XMLCh* fragment = urlSource.getFragment(); - char* fragmentAsCharStar = 0; - if (fragment) - fragmentAsCharStar = XMLString::transcode(fragment, urlSource.getMemoryManager()); - ArrayJanitor<char> janBuf3(fragmentAsCharStar, urlSource.getMemoryManager()); - - const XMLCh* query = urlSource.getQuery(); - char* queryAsCharStar = 0; - if (query) - queryAsCharStar = XMLString::transcode(query, urlSource.getMemoryManager()); - ArrayJanitor<char> janBuf4(queryAsCharStar, urlSource.getMemoryManager()); + XMLURL url(urlSource); + int redirectCount = 0; + SocketJanitor janSock(0); + + do { + // + // Set up a socket. + // + struct hostent* hostEntPtr = 0; + struct sockaddr_in sa; - unsigned short portNumber = (unsigned short) urlSource.getPortNum(); - - // - // Set up a socket. - // - struct hostent* hostEntPtr = 0; - struct sockaddr_in sa; + if ((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL) + { + unsigned long numAddress = inet_addr(hostNameAsCharStar); + if (numAddress == INADDR_NONE) + { + // Call WSAGetLastError() to get the error number. + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_TargetResolution, hostName, fMemoryManager); + } + if ((hostEntPtr = + gethostbyaddr((const char *) &numAddress, + sizeof(unsigned long), AF_INET)) == NULL) + { + // Call WSAGetLastError() to get the error number. + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_TargetResolution, hostName, fMemoryManager); + } + } - if ((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL) - { - unsigned long numAddress = inet_addr(hostNameAsCharStar); - if (numAddress == INADDR_NONE) + memcpy((void *) &sa.sin_addr, + (const void *) hostEntPtr->h_addr, hostEntPtr->h_length); + sa.sin_family = hostEntPtr->h_addrtype; + sa.sin_port = htons((unsigned short)url.getPortNum()); + + janSock.reset(); + fSocketHandle = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0); + if (fSocketHandle == INVALID_SOCKET) { // Call WSAGetLastError() to get the error number. ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_TargetResolution, hostName, fMemoryManager); + XMLExcepts::NetAcc_CreateSocket, url.getURLText(), fMemoryManager); } - if ((hostEntPtr = - gethostbyaddr((const char *) &numAddress, - sizeof(unsigned long), AF_INET)) == NULL) + janSock.reset(&fSocketHandle); + + if (connect(fSocketHandle, (struct sockaddr *) &sa, sizeof(sa)) == SOCKET_ERROR) { // Call WSAGetLastError() to get the error number. ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_TargetResolution, hostName, fMemoryManager); + XMLExcepts::NetAcc_ConnSocket, url.getURLText(), fMemoryManager); } - } - memcpy((void *) &sa.sin_addr, - (const void *) hostEntPtr->h_addr, hostEntPtr->h_length); - sa.sin_family = hostEntPtr->h_addrtype; - sa.sin_port = htons(portNumber); - SOCKET s = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0); - if (s == INVALID_SOCKET) - { - // Call WSAGetLastError() to get the error number. - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_CreateSocket, urlSource.getURLText(), fMemoryManager); - } - SocketJanitor janSock(&s); - - if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) == SOCKET_ERROR) - { - // Call WSAGetLastError() to get the error number. - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_ConnSocket, urlSource.getURLText(), fMemoryManager); - } - - - // Set a flag so we know that the headers have not been read yet. - bool fHeaderRead = false; - - // The port is open and ready to go. - // Build up the http GET command to send to the server. - // To do: We should really support http 1.1. This implementation - // is weak. + // The port is open and ready to go. + // Build up the http GET command to send to the server. + CharBuffer requestBuffer(1023, fMemoryManager); + createHTTPRequest(url, httpInfo, requestBuffer); - memset(fBuffer, 0, sizeof(fBuffer)); + // Send the http request + if(!send(requestBuffer.getRawBuffer(), requestBuffer.getLen())) { + // Call WSAGetLastError() to get the error number. + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager); + } - if(httpInfo==0) - strcpy(fBuffer, "GET "); - else { - switch(httpInfo->fHTTPMethod) { - case XMLNetHTTPInfo::GET: strcpy(fBuffer, "GET "); break; - case XMLNetHTTPInfo::PUT: strcpy(fBuffer, "PUT "); break; - case XMLNetHTTPInfo::POST: strcpy(fBuffer, "POST "); break; + if(httpInfo && httpInfo->fPayload) { + if(!send(httpInfo->fPayload, httpInfo->fPayloadLen)) { + ThrowXMLwithMemMgr1(NetAccessorException, + XMLExcepts::NetAcc_WriteSocket, url.getURLText(), fMemoryManager); + } } - } - strcat(fBuffer, pathAsCharStar); - if (queryAsCharStar != 0) - { - // Tack on a ? before the fragment - strcat(fBuffer,"?"); - strcat(fBuffer, queryAsCharStar); - } + // + // get the response, check the http header for errors from the server. + // + char tmpBuf[1024]; + int ret; - if (fragmentAsCharStar != 0) - { - strcat(fBuffer, fragmentAsCharStar); - } - strcat(fBuffer, " HTTP/1.0\r\n"); + fBuffer.reset(); + while(true) { + ret = recv(fSocketHandle, tmpBuf, sizeof(tmpBuf), 0); + if(ret == SOCKET_ERROR) { + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager); + } + fBuffer.append(tmpBuf, ret); - strcat(fBuffer, "Host: "); - strcat(fBuffer, hostNameAsCharStar); - if (portNumber != 80) - { - strcat(fBuffer, ":"); - int i = strlen(fBuffer); - _itoa(portNumber, fBuffer+i, 10); - } - strcat(fBuffer, "\r\n"); - - const XMLCh* username = urlSource.getUser(); - const XMLCh* password = urlSource.getPassword(); - if (username && password) - { - XMLBuffer userPass(256, fMemoryManager); - userPass.append(username); - userPass.append(chColon); - userPass.append(password); - char* userPassAsCharStar = XMLString::transcode(userPass.getRawBuffer(), fMemoryManager); - ArrayJanitor<char> janBuf(userPassAsCharStar, fMemoryManager); + fBufferPos = strstr(fBuffer.getRawBuffer(), CRLF2X); + if(fBufferPos != 0) { + fBufferPos += 4; + *(fBufferPos - 2) = 0; + break; + } - unsigned int len; - XMLByte* encodedData = Base64::encode((XMLByte *)userPassAsCharStar, strlen(userPassAsCharStar), &len, fMemoryManager); - ArrayJanitor<XMLByte> janBuf2(encodedData, fMemoryManager); - - if (encodedData) - { - // HTTP doesn't want the 0x0A separating the data in chunks of 76 chars per line - XMLByte* authData = (XMLByte*)fMemoryManager->allocate((len+1)*sizeof(XMLByte)); - ArrayJanitor<XMLByte> janBuf(authData, fMemoryManager); - XMLByte* cursor=authData; - for(unsigned int i=0;i<len;i++) - if(encodedData[i]!=chLF) - *cursor++=encodedData[i]; - *cursor++=0; - strcat(fBuffer, "Authorization: Basic "); - strcat(fBuffer, (char*)authData); - strcat(fBuffer, "\r\n"); + fBufferPos = strstr(fBuffer.getRawBuffer(), LF2X); + if(fBufferPos != 0) { + fBufferPos += 2; + *(fBufferPos - 1) = 0; + break; + } } - } - if(httpInfo!=0 && httpInfo->fHeaders!=0) - strncat(fBuffer,httpInfo->fHeaders,httpInfo->fHeadersLen); - - strcat(fBuffer, "\r\n"); - - // Send the http request - int lent = strlen(fBuffer); - int aLent = 0; - if ((aLent = send(s, fBuffer, lent, 0)) != lent) - { - // Call WSAGetLastError() to get the error number. - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_WriteSocket, urlSource.getURLText(), fMemoryManager); - } - - if(httpInfo!=0 && httpInfo->fPayload!=0) { - int aLent = 0; - if ((aLent = send(s, httpInfo->fPayload, httpInfo->fPayloadLen, 0)) != httpInfo->fPayloadLen) - { - // Call WSAGetLastError() to get the error number. - ThrowXMLwithMemMgr1(NetAccessorException, - XMLExcepts::NetAcc_WriteSocket, urlSource.getURLText(), fMemoryManager); + int status = parseResponseStatus(); + if(status < 0) { + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, url.getURLText(), fMemoryManager); } - } - // - // get the response, check the http header for errors from the server. - // - memset(fBuffer, 0, sizeof(fBuffer)); - aLent = recv(s, fBuffer, sizeof(fBuffer)-1, 0); - if (aLent == SOCKET_ERROR || aLent == 0) - { - // Call WSAGetLastError() to get the error number. - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText(), fMemoryManager); - } - - fBufferEnd = fBuffer+aLent; - *fBufferEnd = 0; - - do { - // Find the break between the returned http header and any data. - // (Delimited by a blank line) - // Hang on to any data for use by the first read from this BinHTTPURLInputStream. - // - fBufferPos = strstr(fBuffer, "\r\n\r\n"); - if (fBufferPos != 0) - { - fBufferPos += 4; - *(fBufferPos-2) = 0; - fHeaderRead = true; + if(status == 200) { + // HTTP 200 OK response means we're done. + // We're done + break; } - else - { - fBufferPos = strstr(fBuffer, "\n\n"); - if (fBufferPos != 0) - { - fBufferPos += 2; - *(fBufferPos-1) = 0; - fHeaderRead = true; - } - else - { - // - // Header is not yet read, do another recv() to get more data... - aLent = recv(s, fBufferEnd, (sizeof(fBuffer) - 1) - (fBufferEnd - fBuffer), 0); - if (aLent == SOCKET_ERROR || aLent == 0) - { - // Call WSAGetLastError() to get the error number. - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText(), fMemoryManager); - } - fBufferEnd = fBufferEnd + aLent; - *fBufferEnd = 0; + // a 3xx response means there was an HTTP redirect + else if(status >= 300 && status <= 307) { + redirectCount++; + + XMLCh *newURLString = findHeader("Location"); + ArrayJanitor<XMLCh> janNewURLString(newURLString, fMemoryManager); + + XMLURL newURL(fMemoryManager); + newURL.setURL(url, newURLString); + if(newURL.getProtocol() != XMLURL::HTTP) { + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, newURL.getURLText(), fMemoryManager); } - } - } while(fHeaderRead == false); - // Make sure the header includes an HTTP 200 OK response. - // - char *p = strstr(fBuffer, "HTTP"); - if (p == 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText(), fMemoryManager); - } - - p = strchr(p, ' '); - if (p == 0) - { - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, urlSource.getURLText(), fMemoryManager); - } + url = newURL; - int httpResponse = atoi(p); - if (httpResponse != 200) - { - // Most likely a 404 Not Found error. - // Should recognize and handle the forwarding responses. - // - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, urlSource.getURLText(), fMemoryManager); - } + janHostNameAsCharStar.release(); + hostNameAsCharStar = XMLString::transcode(newURL.getHost(), fMemoryManager); + janHostNameAsCharStar.reset(hostNameAsCharStar, fMemoryManager); + } + else { + // Most likely a 404 Not Found error. + ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::File_CouldNotOpenFile, url.getURLText(), fMemoryManager); + } + } while(redirectCount < 6); - fSocketHandle = (unsigned int) *janSock.release(); + janSock.release(); } @@ -502,17 +625,28 @@ { shutdown(fSocketHandle, SD_BOTH); closesocket(fSocketHandle); + + if(fContentType) fMemoryManager->deallocate(fContentType); } +const XMLCh *BinHTTPURLInputStream::getContentType() const +{ + if(fContentType == 0) { + // mutable + const_cast<XMLCh*&>(fContentType) = findHeader("Content-Type"); + } + return fContentType; +} + // // readBytes // unsigned int BinHTTPURLInputStream::readBytes(XMLByte* const toFill , const unsigned int maxToRead) { - unsigned int len = fBufferEnd - fBufferPos; - if (len > 0) + unsigned int len = fBuffer.getRawBuffer() + fBuffer.getLen() - fBufferPos; + if(len > 0) { // If there's any data left over in the buffer into which we first // read from the server (to get the http header), return that. @@ -526,7 +660,7 @@ // There was no data in the local buffer. // Read some from the socket, straight into our caller's buffer. // - len = recv((SOCKET) fSocketHandle, (char *) toFill, maxToRead, 0); + len = recv(fSocketHandle, (char *) toFill, maxToRead, 0); if (len == SOCKET_ERROR) { // Call WSAGetLastError() to get the error number. diff -ru xerces-c-src_2_8_0-release/src/xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp xerces-c-src_2_8_0/src/xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp --- xerces-c-src_2_8_0-release/src/xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp 2008-02-08 15:30:17.000000000 +0000 +++ xerces-c-src_2_8_0/src/xercesc/util/NetAccessors/WinSock/BinHTTPURLInputStream.hpp 2008-02-08 15:22:45.000000000 +0000 @@ -28,16 +28,138 @@ #include <xercesc/util/BinInputStream.hpp> #include <xercesc/util/Mutexes.hpp> #include <xercesc/util/XMLNetAccessor.hpp> +#include <xercesc/framework/MemoryManager.hpp> + +#define INCL_WINSOCK_API_TYPEDEFS 1 +#include <winsock2.h> + +XERCES_CPP_NAMESPACE_BEGIN // -// This class implements the BinInputStream interface specified by the XML -// parser. +// This class implements a simple expanding character buffer // -struct hostent; -struct sockaddr; +class XMLUTIL_EXPORT CharBuffer +{ +public: + CharBuffer(unsigned int capacity = 1023, + MemoryManager *manager = XMLPlatformUtils::fgMemoryManager) + : fCapacity(capacity), + fIndex(0), + fMemoryManager(manager) + { + fBuffer = (char*)fMemoryManager->allocate((fCapacity + 1) * sizeof(char)); + } + + ~CharBuffer() + { + fMemoryManager->deallocate(fBuffer); + } + + const char* getRawBuffer() const + { + fBuffer[fIndex] = 0; + return fBuffer; + } + + char* getRawBuffer() + { + fBuffer[fIndex] = 0; + return fBuffer; + } + + unsigned int getLen() const + { + return fIndex; + } + + void reset() + { + fIndex = 0; + } + + void append(const char *chars) + { + if(chars != 0 && *chars != 0) { + // get length of chars + unsigned int count = 0; + for(; *(chars+count); ++count); + + if(fIndex + count >= fCapacity) { + insureCapacity(count); + } + memcpy(&fBuffer[fIndex], chars, count * sizeof(char)); + fIndex += count; + } + } + + void append(const char *chars, unsigned int len) + { + if(chars != 0 && len != 0) { + if(fIndex + len >= fCapacity) { + insureCapacity(len); + } + memcpy(&fBuffer[fIndex], chars, len * sizeof(char)); + fIndex += len; + } + } + + void appendDecimalNumber(unsigned int n) + { + if(n >= 10) appendDecimalNumber(n / 10); + + if(fIndex + 1 >= fCapacity) + insureCapacity(1); + + fBuffer[fIndex] = '0' + n; + ++fIndex; + } + + void set(const char *chars) + { + reset(); + append(chars); + } -XERCES_CPP_NAMESPACE_BEGIN +private: + // ----------------------------------------------------------------------- + // Unimplemented constructors and operators + // ----------------------------------------------------------------------- + CharBuffer(const CharBuffer &); + CharBuffer &operator=(const CharBuffer &); + + void insureCapacity(unsigned int extraNeeded) + { + // If we can't handle it, try doubling the buffer size. + unsigned int newCap = (fIndex + extraNeeded) * 2; + + if(newCap > fCapacity) + { + // Allocate new buffer + char* newBuf = (char*)fMemoryManager->allocate((newCap + 1) * sizeof(char)); + + // Copy over the old stuff + memcpy(newBuf, fBuffer, fIndex * sizeof(char)); + + // Clean up old buffer and store new stuff + fMemoryManager->deallocate(fBuffer); + fBuffer = newBuf; + fCapacity = newCap; + } + } + + // ----------------------------------------------------------------------- + // Private data members + // ----------------------------------------------------------------------- + char *fBuffer; + unsigned int fCapacity; + unsigned int fIndex; + MemoryManager *fMemoryManager; +}; +// +// This class implements the BinInputStream interface specified by the XML +// parser. +// class XMLUTIL_EXPORT BinHTTPURLInputStream : public BinInputStream { public : @@ -51,6 +173,8 @@ , const unsigned int maxToRead ); + const XMLCh *getContentType() const; + static void Cleanup(); @@ -60,6 +184,12 @@ // ----------------------------------------------------------------------- BinHTTPURLInputStream(const BinHTTPURLInputStream&); BinHTTPURLInputStream& operator=(const BinHTTPURLInputStream&); + + void createHTTPRequest(const XMLURL &urlSource, const XMLNetHTTPInfo *httpInfo, CharBuffer &buffer); + int parseResponseStatus() const; + XMLCh *findHeader(const char *name) const; + bool send(const char *buf, unsigned int len); + // ----------------------------------------------------------------------- // Private data members // @@ -79,11 +209,12 @@ // that readBytes must return. // ----------------------------------------------------------------------- MemoryManager* fMemoryManager; - unsigned int fSocketHandle; + SOCKET fSocketHandle; unsigned int fBytesProcessed; - char fBuffer[4000]; - char * fBufferEnd; + CharBuffer fBuffer; char * fBufferPos; + XMLCh * fContentType; + static bool fInitialized; static XMLMutex* fInitMutex; @@ -93,12 +224,12 @@ inline static unsigned long inet_addr(const char* cp); inline static hostent* gethostbyaddr(const char* addr,int len,int type); inline static unsigned short htons(unsigned short hostshort); - inline static unsigned int socket(int af,int type,int protocol); - inline static int connect(unsigned int s,const sockaddr* name,int namelen); - inline static int send(unsigned int s,const char* buf,int len,int flags); - inline static int recv(unsigned int s,char* buf,int len,int flags); - inline static int shutdown(unsigned int s,int how); - inline static int closesocket(unsigned int socket); + inline static SOCKET socket(int af,int type,int protocol); + inline static int connect(SOCKET s,const sockaddr* name,int namelen); + inline static int send(SOCKET s,const char* buf,int len,int flags); + inline static int recv(SOCKET s,char* buf,int len,int flags); + inline static int shutdown(SOCKET s,int how); + inline static int closesocket(SOCKET socket); friend class SocketJanitor; }; diff -ru xerces-c-src_2_8_0-release/src/xercesc/util/XMLURL.cpp xerces-c-src_2_8_0/src/xercesc/util/XMLURL.cpp --- xerces-c-src_2_8_0-release/src/xercesc/util/XMLURL.cpp 2008-02-08 15:30:17.000000000 +0000 +++ xerces-c-src_2_8_0/src/xercesc/util/XMLURL.cpp 2008-01-28 01:21:23.000000000 +0000 @@ -1132,6 +1132,10 @@ // If we are at the end, then we are done now if (!*srcPtr) { + if(fHost) { + static const XMLCh slash[] = { chForwardSlash, chNull }; + fPath = XMLString::replicate(slash, fMemoryManager); + } return; } diff -ru xerces-c-src_2_8_0-release/src/xercesc/validators/schema/SchemaElementDecl.hpp xerces-c-src_2_8_0/src/xercesc/validators/schema/SchemaElementDecl.hpp --- xerces-c-src_2_8_0-release/src/xercesc/validators/schema/SchemaElementDecl.hpp 2008-02-08 15:30:17.000000000 +0000 +++ xerces-c-src_2_8_0/src/xercesc/validators/schema/SchemaElementDecl.hpp 2007-11-13 01:31:25.000000000 +0000 @@ -506,7 +506,7 @@ inline bool SchemaElementDecl::isGlobalDecl() const { - return (fEnclosingScope == Grammar::TOP_LEVEL_SCOPE); + return ((unsigned int)fEnclosingScope == Grammar::TOP_LEVEL_SCOPE); } inline SchemaElementDecl*