📄 sbinethttpstream.cpp
字号:
/****************License************************************************ * * Copyright 2000-2003. ScanSoft, Inc. * * Use of this software is subject to notices and obligations set forth * in the SpeechWorks Public License - Software Version 1.2 which is * included with this software. * * ScanSoft is a registered trademark of ScanSoft, Inc., and OpenSpeech, * SpeechWorks and the SpeechWorks logo are registered trademarks or * trademarks of SpeechWorks International, Inc. in the United States * and other countries. * ***********************************************************************/ #ifndef _SB_USE_STD_NAMESPACE #define _SB_USE_STD_NAMESPACE #endif #ifdef WIN32 #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #endif #include <sys/timeb.h> // for _ftime( )/ftime( ) #include "VXIvalue.h" #include "VXIinet.h" #include "VXItrd.h" #include "SBinetLog.h" #include "SBinetURL.h" #include "SBinetHttpStream.hpp" #include "SBinetChannel.h" #include "SBinetHttpConnection.hpp" #include "SBinetValidator.h" #include "SBinetCookie.h" #include "SBinetUtils.hpp" #include "SWITimeWatch.hpp" #include "util_date.h" #include "ap_ctype.h" #include "HttpUtils.hpp" #include <SWIsocket.hpp> #include <SWIdataOutputStream.hpp> #include <SWIbufferedInputStream.hpp> #include <SWIbufferedOutputStream.hpp> #define HTTP_UNDEFINED -1234 /* No HTTP error code yet */ #define READ_CHUNK_SIZE 128 * 1024 // Read from socket in 128 Kb chunks SBinetHttpStream::SBinetHttpStream(SBinetURL* url, SubmitMethod method, SBinetChannel* ch, VXIlogInterface *log, VXIunsigned diagLogBase): SBinetStoppableStream(url, log, diagLogBase), _HttpStatus(HTTP_UNDEFINED), _leftToRead(~0), _chunked(false), _method(method), _channel(ch), _connection(NULL), _inputStream(NULL), _outputStream(NULL), _closeConnection(TRUE), _validator(NULL), _connectionAborted(FALSE) {} SBinetHttpStream::~SBinetHttpStream() { delete _validator; Close(); } VXIinetResult SBinetHttpStream::initSocket(SubmitMethod method, const VXIMap *properties, VXIMap *streamInfo) { _connection = _channel->getHttpConnection(_url, properties); if (_connection == NULL) { Error(262, L"%s%s", L"URL", _url->getAbsolute()); return VXIinet_RESULT_FETCH_ERROR; } SWITimeWatch timeWatch; timeWatch.start(); switch (_connection->connect(getDelay())) { case SWIstream::TIMED_OUT: Error(241, NULL); return VXIinet_RESULT_FETCH_TIMEOUT; break; case SWIstream::SUCCESS: break; default: Error(244, L"%s%s", L"URL", _url->getAbsolute()); return VXIinet_RESULT_FETCH_ERROR; } _inputStream = _connection->getInputStream(); _outputStream = _connection->getOutputStream(); Diag(MODULE_SBINET_TIMING_TAGID, L"SBinetHttpStream::initSocket", L"%i msecs, Connect to socket", timeWatch.getElapsed()); writeDebugTimeStamp(); if (method == SBinetHttpStream::GET_METHOD) _channel->writeString(_outputStream, "GET "); else _channel->writeString(_outputStream, "POST "); if (_connection->usesProxy()) _channel->writeString(_outputStream, _url->getNAbsolute()); else _channel->writeString(_outputStream, _url->getNPath()); _channel->writeString(_outputStream, " HTTP/1.1" CRLF); _channel->writeString(_outputStream, "Accept: */*" CRLF); // Write HOST header. _channel->writeString(_outputStream, "Host: "); _channel->writeString(_outputStream, _url->getNHost()); int defaultPort = _url->getProtocol() == SBinetURL::HTTP_PROTOCOL ? 80 : 443; int port = _url->getPort(); if (port != defaultPort) { _channel->writeString(_outputStream, ":"); _channel->writeInt(_outputStream, port); } _channel->writeString(_outputStream, CRLF); // Write USER-AGENT header. _channel->writeString(_outputStream, "User-Agent: "); _channel->writeString(_outputStream, _channel->getUserAgent()); _channel->writeString(_outputStream, CRLF); // Write REFERER header. SBinetNString baseUrl = _url->getNBase(); if (baseUrl.length() > 0) { // Cut query arguments, if present VXIunsigned queryArgsSeparator = baseUrl.find('?'); if (queryArgsSeparator < baseUrl.length()) baseUrl.resize(queryArgsSeparator); if (baseUrl.length() > 0) { _channel->writeString(_outputStream, "Referer: "); _channel->writeString(_outputStream, baseUrl.c_str()); _channel->writeString(_outputStream, CRLF); } } SBinetUtils::getInteger(properties, INET_CLOSE_CONNECTION, _closeConnection); if (_closeConnection) { _channel->writeString(_outputStream, "Connection: close" CRLF); } VXIint32 maxAge = -1; VXIint32 maxStale = -1; getCacheInfo(properties, maxAge, maxStale); if (maxAge != -1) { _channel->writeString(_outputStream, "Cache-Control: max-age="); _channel->writeInt(_outputStream, maxAge); _channel->writeString(_outputStream, CRLF); } if (maxStale != -1) { _channel->writeString(_outputStream, "Cache-Control: max-stale="); _channel->writeInt(_outputStream, maxStale); _channel->writeString(_outputStream, CRLF); } time_t lastModified = (time_t) -1; SBinetNString etag; getModInfo(properties, lastModified, etag); if (method == SBinetHttpStream::GET_METHOD && lastModified != (time_t) -1) { char lastModStr[32]; ap_gm_timestr_822(lastModStr, lastModified); _channel->writeString(_outputStream, "If-Modified-Since: "); _channel->writeString(_outputStream, lastModStr); _channel->writeString(_outputStream, CRLF); } if (etag[0]) { _channel->writeString(_outputStream, "If-None-Match: "); _channel->writeString(_outputStream, etag.c_str()); _channel->writeString(_outputStream, CRLF); } if (_channel->cookiesEnabled()) { _channel->collectCookies(_outputStream, _url->getNHost(), _url->getNPath()); } return VXIinet_RESULT_SUCCESS; } VXIinetResult SBinetHttpStream::doGet(VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo) { VXIinetResult rc = initSocket(GET_METHOD, properties, streamInfo); if (rc != VXIinet_RESULT_SUCCESS) return rc; _channel->writeString(_outputStream, CRLF); if (_outputStream->flush() != SWIstream::SUCCESS) rc = VXIinet_RESULT_IO_ERROR; return rc; } /* * POST simple form data. Don't know how to combine Form data and audio in multipart POST */ VXIinetResult SBinetHttpStream::doPost(VXIint32 flags, const VXIMap *properties, VXIMap *streamInfo) { const VXIMap *queryArgs = (const VXIMap *)VXIMapGetProperty(properties, INET_URL_QUERY_ARGS); SBinetNString queryArgsStr; VXIint argsLen; EncodingType encodingType = getEncodingType(properties); const char *encodingStr; if (encodingType == TYPE_MULTIPART) { encodingStr = SB_MULTIPART; queryArgsStr = _url->queryArgsToMultipart(queryArgs); argsLen = queryArgsStr.length(); Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetHttpStream::doPost", L"Performing multipart POST, data size %i", argsLen); } else { encodingStr = SB_URLENCODED; queryArgsStr = _url->queryArgsToNString(queryArgs); argsLen = queryArgsStr.length(); Diag(MODULE_SBINET_STREAM_TAGID, L"SBinetHttpStream::doPost", L"Performing URL-encoded POST, data size %i", argsLen); } VXIinetResult rc = initSocket(POST_METHOD, properties, streamInfo); if (rc != VXIinet_RESULT_SUCCESS) return rc; _channel->writeString(_outputStream, "Expect: 100-continue" CRLF); _channel->writeString(_outputStream, "Content-Length: "); _channel->writeInt(_outputStream, argsLen); _channel->writeString(_outputStream, CRLF); _channel->writeString(_outputStream, "Content-Type: "); _channel->writeString(_outputStream, encodingStr); _channel->writeString(_outputStream, CRLF CRLF); if (_outputStream->flush() != SWIstream::SUCCESS) { return VXIinet_RESULT_IO_ERROR; } // Wait for input stream to be ready. If time-out, just send data anyway. // If we don't time out, we should be able to get an HTTP_CONTINUE. VXIint32 continueTimeout = SBinetChannel::getPostContinueTimeout(); int maxDelay = getDelay(); if (continueTimeout < 0 || (maxDelay >=0 && continueTimeout > maxDelay)) continueTimeout = maxDelay; switch (_inputStream->waitReady(continueTimeout)) { case SWIstream::SUCCESS: // Read the HTTP_CONTINUE header if ((rc = getHeaderInfo(streamInfo)) != VXIinet_RESULT_SUCCESS) return rc; if (_HttpStatus != SBinetHttpUtils::HTTP_CONTINUE) return VXIinet_RESULT_FETCH_ERROR; break; case SWIstream::TIMED_OUT: // We still have to send the body of the message. This is done // after the switch anyway so we do nothing. break; default: // I/O error on the stream. Just return an error. return VXIinet_RESULT_FETCH_ERROR; } if (encodingType == TYPE_MULTIPART) { _channel->writeData(_outputStream, queryArgsStr.data(), argsLen); } else { _channel->writeString(_outputStream, queryArgsStr.c_str()); } if (_outputStream->flush() != SWIstream::SUCCESS) rc = VXIinet_RESULT_IO_ERROR; return rc; } bool SBinetHttpStream::handleRedirect(VXIMap *streamInfo) { const VXIchar *location; switch (_HttpStatus) { case SBinetHttpUtils::HTTP_SEE_OTHER: // This return code implies that we change a POST into a GET. _method = GET_METHOD; // no break: intentional case SBinetHttpUtils::HTTP_MULTIPLE_CHOICES: case SBinetHttpUtils::HTTP_PERM_REDIRECT: case SBinetHttpUtils::HTTP_FOUND: case SBinetHttpUtils::HTTP_TEMP_REDIRECT: location = SBinetUtils::getString(streamInfo, L"Location"); if (location == NULL || !*location) { Error(247, L"%s%s", L"URL", _url->getAbsolute()); return false; } if (_url->parse(location, _url->getAbsolute()) != VXIinet_RESULT_SUCCESS) { Error(248, L"%s%s%s%s", L"URL", _url->getAbsolute(), L"Location", location); return false; } return true; break; default: return false; } } // stupid function required because the people who designed VXIMap, in their // great wisdom, did not include a VXIMapClear function or the ability for the // iterator to delete the current entry. static void clearMap(VXIMap *streamInfo) { VXIunsigned n = VXIMapNumProperties(streamInfo); const VXIchar **keys = new const VXIchar *[n]; const VXIchar *key; const VXIValue *value; int i = 0; VXIMapIterator *mapIterator = VXIMapGetFirstProperty(streamInfo, &key, &value ); do { if (key != NULL) { keys[i++] = key; } } while (VXIMapGetNextProperty(mapIterator, &key, &value) == VXIvalue_RESULT_SUCCESS); VXIMapIteratorDestroy(&mapIterator); i--; while (--i >= 0) { VXIMapDeleteProperty(streamInfo, keys[i]); } delete [] keys; } VXIinetResult SBinetHttpStream::Open(VXIint32 flags, const VXIMap *properties,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -