OGRUKOOAP190Layer::OGRUKOOAP190Layer( const char* pszFilename, VSILFILE* fpIn ) : poSRS(nullptr), fp(fpIn), bUseEastingNorthingAsGeometry(CPLTestBool( CPLGetConfigOption("UKOOAP190_USE_EASTING_NORTHING", "NO"))), nYear(0) { nNextFID = 0; bEOF = false; poFeatureDefn = new OGRFeatureDefn( CPLGetBasename(pszFilename) ); SetDescription( poFeatureDefn->GetName() ); poFeatureDefn->Reference(); poFeatureDefn->SetGeomType( wkbPoint ); for( int i = 0; i < static_cast<int>(sizeof(UKOOAP190Fields) / sizeof(UKOOAP190Fields[0])); i++ ) { OGRFieldDefn oField( UKOOAP190Fields[i].pszName, UKOOAP190Fields[i].eType ); poFeatureDefn->AddFieldDefn( &oField ); } ParseHeaders(); poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); }
//Parses the request QTSS_Error HTTPRequest::Parse() { Assert(fRequestHeader.Ptr != NULL); StringParser parser(&fRequestHeader); // Store the request line (used for logging) // (ex: GET /index.html HTTP/1.0) StringParser requestLineParser(&fRequestHeader); requestLineParser.ConsumeUntil(&fRequestLine, StringParser::sEOLMask); // Parse request line returns an error if there is an error in the // request URI or the formatting of the request line. // If the method or version are not found, they are set // to httpIllegalMethod or httpIllegalVersion respectively, // and QTSS_NoErr is returned. // 解析第一行 QTSS_Error err = ParseRequestLine(&parser); if (err != QTSS_NoErr) return err; // Parse headers and set values of headers into fFieldValues array err = ParseHeaders(&parser); if (err != QTSS_NoErr) return err; return QTSS_NoErr; }
OGRUKOOAP190Layer::OGRUKOOAP190Layer( const char* pszFilename, VSILFILE* fp ) { this->fp = fp; nNextFID = 0; bEOF = FALSE; poSRS = NULL; nYear = 0; poFeatureDefn = new OGRFeatureDefn( CPLGetBasename(pszFilename) ); SetDescription( poFeatureDefn->GetName() ); poFeatureDefn->Reference(); poFeatureDefn->SetGeomType( wkbPoint ); for(int i=0;i<(int)(sizeof(UKOOAP190Fields)/sizeof(UKOOAP190Fields[0]));i++) { OGRFieldDefn oField( UKOOAP190Fields[i].pszName, UKOOAP190Fields[i].eType ); poFeatureDefn->AddFieldDefn( &oField ); } bUseEastingNorthingAsGeometry = CSLTestBoolean(CPLGetConfigOption("UKOOAP190_USE_EASTING_NORTHING", "NO")); ParseHeaders(); poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); }
void ParseFile() { for (;;) { uint8_t *objectStart = cursor; GUIDType type = ReadGUID(); uint64_t size = ReadQWord(); uint8_t *next = objectStart + size; printf( "Object size: %llu\n", size ); switch (type) { case GUIDHeader: printf( "Header GUID\n" ); ParseHeaders(); break; case GUIDData: printf( "Found Data object\n" ); return; case GUIDUnknown: default: printf( "Unknown GUID\n" ); break; } cursor = next; } }
wxString mHTTP::GetResponseMessage() { if (m_messagereceived.IsEmpty()) { ParseHeaders(); } return m_messagereceived; };
bool BaseHTTPProtocol::SignalInputData(IOBuffer &buffer) { DEBUG_HTTP("-------------------"); DEBUG_HTTP("%s", STR(*this)); DEBUG_HTTP("_state: %s", (_state == HTTP_STATE_HEADERS) ? "HTTP_STATE_HEADERS" : (_state == HTTP_STATE_PAYLOAD) ? "HTTP_STATE_PAYLOAD" : "UNKNOWN"); //1. Get the first line and the headers if necessary if (_state == HTTP_STATE_HEADERS) { DEBUG_HTTP("Parse the headers"); if (!ParseHeaders(buffer)) { FATAL("Unable to read response headers: %s", STR(*this)); return false; } } DEBUG_HTTP("_continueAfterParseHeaders: %d", _continueAfterParseHeaders); if (!_continueAfterParseHeaders) return true; //2. Are we still in the "get headers state"? If so, wait for more data DEBUG_HTTP("new value of _state: %s", (_state == HTTP_STATE_HEADERS) ? "HTTP_STATE_HEADERS" : (_state == HTTP_STATE_PAYLOAD) ? "HTTP_STATE_PAYLOAD" : "UNKNOWN"); if (_state != HTTP_STATE_PAYLOAD) { return true; } DEBUG_HTTP("_chunkedContent: %d", _chunkedContent); //3. Turning point in processing if (_chunkedContent) { //4. We deal with chunked content DEBUG_HTTP("begin chunk content handling"); if (!HandleChunkedContent(buffer)) { FATAL("Unable to handle chunked content: %s", STR(*this)); return false; } } else { //5. We deal with length-specified type of content DEBUG_HTTP("begin fixed length content handling"); if (!HandleFixedLengthContent(buffer)) { FATAL("Unable to handle fixed length content: %s", STR(*this)); return false; } } //6. Are we in the get headers state? if so, we might have a new request //on the pipe. DEBUG_HTTP("brand new value of _state: %s", (_state == HTTP_STATE_HEADERS) ? "HTTP_STATE_HEADERS" : (_state == HTTP_STATE_PAYLOAD) ? "HTTP_STATE_PAYLOAD" : "UNKNOWN"); if (_state == HTTP_STATE_HEADERS) { DEBUG_HTTP("Call SignalInputData again"); //7. So, get to work again... return SignalInputData(buffer); } else { //8 We are done :) DEBUG_HTTP("Done"); return true; } }
void WebProcessor::Execute() { m_gzip =false; m_userAccess = uaControl; m_authInfo[0] = '\0'; m_authToken[0] = '\0'; ParseHeaders(); if (m_httpMethod == hmPost && m_contentLen <= 0) { error("Invalid-request: content length is 0"); return; } if (m_httpMethod == hmOptions) { SendOptionsResponse(); return; } ParseUrl(); if (!CheckCredentials()) { SendAuthResponse(); return; } if (m_httpMethod == hmPost) { // reading http body (request content) m_request.Reserve(m_contentLen); m_request[m_contentLen] = '\0'; if (!m_connection->Recv(m_request, m_contentLen)) { error("Invalid-request: could not read data"); return; } debug("Request=%s", *m_request); } debug("request received from %s", m_connection->GetRemoteAddr()); Dispatch(); }
bool BaseHTTPProtocol::SignalInputData(IOBuffer &buffer) { //1. Get the first line and the headers if necessary if (_state == HTTP_STATE_HEADERS) { if (!ParseHeaders(buffer)) { FATAL("Unable to read response headers"); return false; } } if (!_continueAfterParseHeaders) return true; //2. Are we still in the "get headers state"? If so, wait for more data if (_state != HTTP_STATE_PAYLOAD) { return true; } //3. Turning point in processing if (_chunkedContent) { //4. We deal with chunked content if (!HandleChunkedContent(buffer)) { FATAL("Unable to handle chunked content"); return false; } } else { //5. We deal with length-specified type of content if (!HandleFixedLengthContent(buffer)) { FATAL("Unable to handle fixed length content"); return false; } } //6. Are we in the get headers state? if so, we might have a new request //on the pipe. if (_state == HTTP_STATE_HEADERS) { //7. So, get to work again... return SignalInputData(buffer); } else { //8 We are done :) return true; } }
void au::SessionTokenTestConnection::ReadHeaders() { auto self(shared_from_this()); asio::async_read_until( request_->ssl_stream, request_->read_buffer_, "\r\n\r\n", [this, self]( boost::system::error_code ec, std::size_t bytes_transferred ) { if (ec) { std::cout << "ReadHeaders: Got error: " << ec.message() << std::endl; request_->Fail(HttpStatusCode::bad_request); return; } ParseHeaders( bytes_transferred ); }); }
Request::Request(std::string raw) { std::vector<std::string> lines; // Split the raw data in to lines // "The escape sequence \R matches any line ending character sequence" boost::split_regex(lines, raw, boost::regex("\\R")); if (lines.size() > 0) { // Read the start line boost::smatch m; bool match = boost::regex_match(lines.at(0), m, boost::regex("^(.*) (.*) (.*)$")); if (match) m_StartLine = { m[1].str(), m[2].str(), m[3].str() }; else { std::cerr << "Failed to read request start line" << std::endl; return; } // Parse ALL the headers! m_Headers = ParseHeaders(&lines); } }
void CHttpClient::Process() { // Do we have a request start and has the request timed out? if (m_uiRequestStart > 0 && (SharedUtility::GetTime() - m_uiRequestStart) >= m_uiRequestTimeout) { // Set the status to none m_status = HTTP_STATUS_NONE; // Request timed out, set the last error m_lastError = HTTP_ERROR_REQUEST_TIMEOUT; // Reset the request start m_uiRequestStart = 0; // Disconnect from the host Disconnect(); return; } // Are we not in idle status? if (m_status != HTTP_STATUS_NONE) { switch (m_status) { case HTTP_STATUS_GET_DATA: { // Prepare a buffer char szBuffer[MAX_BUFFER]; memset(szBuffer, 0, sizeof(szBuffer)); // Try to read from the socket int iBytesRecieved = Read(szBuffer, sizeof(szBuffer)); int iHeaderSize = 0; // Did we get anything? if (iBytesRecieved > 0) { // Are the headers empty? if (m_headerMap.empty()) { // Parse the headers if (!ParseHeaders(szBuffer, iBytesRecieved, iHeaderSize)) { // We don't have a header, set the status m_status = HTTP_STATUS_INVALID; // Set the last error m_lastError = HTTP_ERROR_NO_HEADER; // Reset the request start m_uiRequestStart = 0; // Disconnect from the host Disconnect(); return; } // Do we not have any data? if (iBytesRecieved == 0) return; } // Skip the header data if we have any char * szData = (iBytesRecieved ? (szBuffer + iHeaderSize) : NULL); // Call the receive handler if we have one if (m_pfnReceiveHandler) { if (m_pfnReceiveHandler(szData, iBytesRecieved, m_pReceiveHandlerUserData)) m_strData.Append(szData, iBytesRecieved); } // Write response data to file if we have one set else if (m_fFile != NULL) fwrite(szData, 1, iBytesRecieved, m_fFile); } else if (iBytesRecieved == 0) { // We got data, set the status m_status = HTTP_STATUS_GOT_DATA; // Reset the request start m_uiRequestStart = 0; // Disconnect from the host Disconnect(); } } break; } } }
/* Set up all the necessary jk_* workspace based on the current HTTP request. */ static int InitService(private_ws_t *ws, jk_ws_service_t *s) { /* This is the only fixed size buffer left. It won't be overflowed * because the Domino API that reads into the buffer accepts a length * constraint, and it's unlikely ever to be exhausted because the * strings being will typically be short, but it's still aesthetically * troublesome. */ char workBuf[16 * 1024]; FilterRequest fr; char *hdrs, *qp; int hdrsz; int errID; int hdrCount; int rc /*, dummy*/; static char *methodName[] = { "", "HEAD", "GET", "POST", "PUT", "DELETE" }; rc = ws->context->GetRequest(ws->context, &fr, &errID); s->jvm_route = NULL; s->start_response = StartResponse; s->read = Read; s->write = Write; s->req_uri = jk_pool_strdup(&ws->p, fr.URL); s->query_string = NULL; if (qp = strchr(s->req_uri, '?'), qp != NULL) { *qp++ = '\0'; if (strlen(qp)) s->query_string = qp; } GETVARIABLE("AUTH_TYPE", &s->auth_type, ""); GETVARIABLE("REMOTE_USER", &s->remote_user, ""); GETVARIABLE("SERVER_PROTOCOL", &s->protocol, ""); GETVARIABLE("REMOTE_HOST", &s->remote_host, ""); GETVARIABLE("REMOTE_ADDR", &s->remote_addr, ""); GETVARIABLE("SERVER_NAME", &s->server_name, ""); GETVARIABLEINT("SERVER_PORT", &s->server_port, 80); GETVARIABLE("SERVER_SOFTWARE", &s->server_software, SERVERDFLT); GETVARIABLEINT("CONTENT_LENGTH", &s->content_length, 0); /* SSL Support */ GETVARIABLEBOOL("HTTPS", &s->is_ssl, 0); if (ws->reqData->requestMethod < 0 || ws->reqData->requestMethod >= sizeof(methodName) / sizeof(methodName[0])) return JK_FALSE; s->method = methodName[ws->reqData->requestMethod]; s->headers_names = NULL; s->headers_values = NULL; s->num_headers = 0; s->ssl_cert_len = fr.clientCertLen; s->ssl_cert = fr.clientCert; s->ssl_cipher = NULL; /* required by Servlet 2.3 Api */ s->ssl_session = NULL; #if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1) s->ssl_key_size = -1; /* required by Servlet 2.3 Api, added in jtc */ #endif if (s->is_ssl) { int dummy; #if 0 char *sslNames[] = { "CERT_ISSUER", "CERT_SUBJECT", "CERT_COOKIE", "CERT_FLAGS", "CERT_SERIALNUMBER", "HTTPS_SERVER_SUBJECT", "HTTPS_SECRETKEYSIZE", "HTTPS_SERVER_ISSUER", "HTTPS_KEYSIZE" }; char *sslValues[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; unsigned i, varCount = 0; #endif DEBUG(("SSL request\n")); #if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1) /* Read the variable into a dummy variable: we do this for the side effect of * reading it into workBuf. */ GETVARIABLEINT("HTTPS_KEYSIZE", &dummy, 0); if (workBuf[0] == '[') s->ssl_key_size = atoi(workBuf+1); #else (void) dummy; #endif #if 0 for (i = 0; i < sizeof(sslNames)/sizeof(sslNames[0]); i++) { GETVARIABLE(sslNames[i], &sslValues[i], NULL); if (sslValues[i]) varCount++; } /* Andy, some SSL vars must be mapped directly in s->ssl_cipher, * ssl->session and s->ssl_key_size * ie: * Cipher could be "RC4-MD5" * KeySize 128 (bits) * SessionID a string containing the UniqID used in SSL dialogue */ if (varCount > 0) { unsigned j; s->attributes_names = jk_pool_alloc(&ws->p, varCount * sizeof (char *)); s->attributes_values = jk_pool_alloc(&ws->p, varCount * sizeof (char *)); j = 0; for (i = 0; i < sizeof(sslNames)/sizeof(sslNames[0]); i++) { if (sslValues[i]) { s->attributes_names[j] = sslNames[i]; s->attributes_values[j] = sslValues[i]; j++; } } s->num_attributes = varCount; } #endif } /* Duplicate all the headers now */ hdrsz = ws->reqData->GetAllHeaders(ws->context, &hdrs, &errID); DEBUG(("\nGot headers (length %d)\n--------\n%s\n--------\n\n", hdrsz, hdrs)); s->headers_names = s->headers_values = NULL; hdrCount = ParseHeaders(ws, hdrs, hdrsz, s); DEBUG(("Found %d headers\n", hdrCount)); s->num_headers = hdrCount; s->headers_names = jk_pool_alloc(&ws->p, hdrCount * sizeof(char *)); s->headers_values = jk_pool_alloc(&ws->p, hdrCount * sizeof(char *)); hdrCount = ParseHeaders(ws, hdrs, hdrsz, s); return JK_TRUE; }
// nsIStreamListener implementation NS_IMETHODIMP nsMultiMixedConv::OnDataAvailable(nsIRequest *request, nsISupports *context, nsIInputStream *inStr, uint64_t sourceOffset, uint32_t count) { nsresult rv = NS_OK; AutoFree buffer(nullptr); uint32_t bufLen = 0, read = 0; NS_ASSERTION(request, "multimixed converter needs a request"); nsCOMPtr<nsIChannel> channel = do_QueryInterface(request, &rv); if (NS_FAILED(rv)) return rv; // fill buffer { bufLen = count + mBufLen; NS_ENSURE_TRUE((bufLen >= count) && (bufLen >= mBufLen), NS_ERROR_FAILURE); buffer = (char *) malloc(bufLen); if (!buffer) return NS_ERROR_OUT_OF_MEMORY; if (mBufLen) { // incorporate any buffered data into the parsing memcpy(buffer, mBuffer, mBufLen); free(mBuffer); mBuffer = 0; mBufLen = 0; } rv = inStr->Read(buffer + (bufLen - count), count, &read); if (NS_FAILED(rv) || read == 0) return rv; NS_ASSERTION(read == count, "poor data size assumption"); } char *cursor = buffer; if (mFirstOnData) { // this is the first OnData() for this request. some servers // don't bother sending a token in the first "part." This is // illegal, but we'll handle the case anyway by shoving the // boundary token in for the server. mFirstOnData = false; NS_ASSERTION(!mBufLen, "this is our first time through, we can't have buffered data"); const char * token = mToken.get(); PushOverLine(cursor, bufLen); bool needMoreChars = bufLen < mTokenLen + 2; nsAutoCString firstBuffer(buffer, bufLen); int32_t posCR = firstBuffer.Find("\r"); if (needMoreChars || (posCR == kNotFound)) { // we don't have enough data yet to make this comparison. // skip this check, and try again the next time OnData() // is called. mFirstOnData = true; } else if (mPackagedApp) { // We need to check the line starts with -- if (!StringBeginsWith(firstBuffer, NS_LITERAL_CSTRING("--"))) { return NS_ERROR_FAILURE; } // If the boundary was set in the header, // we need to check it matches with the one in the file. if (mTokenLen && !StringBeginsWith(Substring(firstBuffer, 2), mToken)) { return NS_ERROR_FAILURE; } // Save the token. if (!mTokenLen) { mToken = nsCString(Substring(firstBuffer, 2).BeginReading(), posCR - 2); mTokenLen = mToken.Length(); } cursor = buffer; } else if (!PL_strnstr(cursor, token, mTokenLen + 2)) { char *newBuffer = (char *) realloc(buffer, bufLen + mTokenLen + 1); if (!newBuffer) return NS_ERROR_OUT_OF_MEMORY; buffer = newBuffer; memmove(buffer + mTokenLen + 1, buffer, bufLen); memcpy(buffer, token, mTokenLen); buffer[mTokenLen] = '\n'; bufLen += (mTokenLen + 1); // need to reset cursor to the buffer again (bug 100595) cursor = buffer; } } char *token = nullptr; // This may get initialized by ParseHeaders and the resulting // HttpResponseHead will be passed to nsPartChannel by SendStart if (mProcessingHeaders) { // we were not able to process all the headers // for this "part" given the previous buffer given to // us in the previous OnDataAvailable callback. bool done = false; rv = ParseHeaders(channel, cursor, bufLen, &done); if (NS_FAILED(rv)) return rv; if (done) { mProcessingHeaders = false; rv = SendStart(channel); if (NS_FAILED(rv)) return rv; } } int32_t tokenLinefeed = 1; while ( (token = FindToken(cursor, bufLen)) ) { if (((token + mTokenLen) < (cursor + bufLen)) && (*(token + mTokenLen + 1) == '-')) { // This was the last delimiter so we can stop processing rv = SendData(cursor, LengthToToken(cursor, token)); if (NS_FAILED(rv)) return rv; if (mPartChannel) { mPartChannel->SetIsLastPart(); } return SendStop(NS_OK); } if (!mNewPart && token > cursor) { // headers are processed, we're pushing data now. NS_ASSERTION(!mProcessingHeaders, "we should be pushing raw data"); rv = SendData(cursor, LengthToToken(cursor, token)); bufLen -= token - cursor; if (NS_FAILED(rv)) return rv; } // XXX else NS_ASSERTION(token == cursor, "?"); token += mTokenLen; bufLen -= mTokenLen; tokenLinefeed = PushOverLine(token, bufLen); if (mNewPart) { // parse headers mNewPart = false; cursor = token; bool done = false; rv = ParseHeaders(channel, cursor, bufLen, &done); if (NS_FAILED(rv)) return rv; if (done) { rv = SendStart(channel); if (NS_FAILED(rv)) return rv; } else { // we haven't finished processing header info. // we'll break out and try to process later. mProcessingHeaders = true; break; } } else { mNewPart = true; // Reset state so we don't carry it over from part to part mContentType.Truncate(); mContentLength = UINT64_MAX; mContentDisposition.Truncate(); mIsByteRangeRequest = false; mByteRangeStart = 0; mByteRangeEnd = 0; rv = SendStop(NS_OK); if (NS_FAILED(rv)) return rv; // reset the token to front. this allows us to treat // the token as a starting token. token -= mTokenLen + tokenLinefeed; bufLen += mTokenLen + tokenLinefeed; cursor = token; } } // at this point, we want to buffer up whatever amount (bufLen) // we have leftover. However, we *always* want to ensure that // we buffer enough data to handle a broken token. // carry over uint32_t bufAmt = 0; if (mProcessingHeaders) bufAmt = bufLen; else if (bufLen) { // if the data ends in a linefeed, and we're in the middle // of a "part" (ie. mPartChannel exists) don't bother // buffering, go ahead and send the data we have. Otherwise // if we don't have a channel already, then we don't even // have enough info to start a part, go ahead and buffer // enough to collect a boundary token. if (!mPartChannel || !(cursor[bufLen-1] == nsCRT::LF) ) bufAmt = std::min(mTokenLen - 1, bufLen); } if (bufAmt) { rv = BufferData(cursor + (bufLen - bufAmt), bufAmt); if (NS_FAILED(rv)) return rv; bufLen -= bufAmt; } if (bufLen) { rv = SendData(cursor, bufLen); if (NS_FAILED(rv)) return rv; } return rv; }
/***************************************************************************** * Open: initializes ES structures *****************************************************************************/ static int Open( vlc_object_t * p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; const uint8_t *p_peek; es_format_t fmt; /* Have a peep at the show. */ if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC; if( p_peek[0]!='f' || p_peek[1]!='L' || p_peek[2]!='a' || p_peek[3]!='C' ) { if( !p_demux->obj.force && !demux_IsContentType( p_demux, "audio/flac" ) ) return VLC_EGENERIC; /* User forced */ msg_Err( p_demux, "this doesn't look like a flac stream, " "continuing anyway" ); } p_sys = malloc( sizeof( demux_sys_t ) ); if( unlikely(p_sys == NULL) ) return VLC_ENOMEM; p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys; p_sys->b_start = true; p_sys->i_next_block_flags = 0; p_sys->p_packetizer = NULL; p_sys->p_meta = NULL; p_sys->i_length = 0; p_sys->i_pts = VLC_TS_INVALID; p_sys->p_es = NULL; p_sys->p_current_block = NULL; TAB_INIT( p_sys->i_seekpoint, p_sys->seekpoint ); TAB_INIT( p_sys->i_attachments, p_sys->attachments); TAB_INIT( p_sys->i_title_seekpoints, p_sys->pp_title_seekpoints ); p_sys->i_cover_idx = 0; p_sys->i_cover_score = 0; es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_FLAC ); /* We need to read and store the STREAMINFO metadata into fmt extra */ if( ParseHeaders( p_demux, &fmt ) ) goto error; /* Load the FLAC packetizer */ p_sys->p_packetizer = demux_PacketizerNew( p_demux, &fmt, "flac" ); if( !p_sys->p_packetizer ) goto error; if( p_sys->i_cover_idx < p_sys->i_attachments ) { char psz_url[128]; if( !p_sys->p_meta ) p_sys->p_meta = vlc_meta_New(); snprintf( psz_url, sizeof(psz_url), "attachment://%s", p_sys->attachments[p_sys->i_cover_idx]->psz_name ); vlc_meta_Set( p_sys->p_meta, vlc_meta_ArtworkURL, psz_url ); } p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_in ); if( !p_sys->p_es ) goto error; return VLC_SUCCESS; error: Close( p_this ); return VLC_EGENERIC; }
// Extract HTTP headers via temporary file with -D switch. // HTTP status code is extracted from curl output (-w switches). // Redirects are handled recursively. TODO(AlexZ): avoid infinite redirects loop. bool HttpClient::RunHttpRequest() { ScopedRemoveFile headers_deleter(GetTmpFileName()); ScopedRemoveFile body_deleter; ScopedRemoveFile received_file_deleter; string cmd = "curl -s -w '%{http_code}' -X " + m_httpMethod + " -D '" + headers_deleter.m_fileName + "' "; for (auto const & header : m_headers) { cmd += "-H '" + header.first + ": " + header.second + "' "; } if (!m_cookies.empty()) cmd += "-b '" + m_cookies + "' "; if (!m_bodyData.empty()) { body_deleter.m_fileName = GetTmpFileName(); // POST body through tmp file to avoid breaking command line. if (!WriteToFile(body_deleter.m_fileName, m_bodyData)) return false; // TODO(AlexZ): Correctly clean up this internal var to avoid client confusion. m_inputFile = body_deleter.m_fileName; } // Content-Length is added automatically by curl. if (!m_inputFile.empty()) cmd += "--data-binary '@" + m_inputFile + "' "; // Use temporary file to receive data from server. // If user has specified file name to save data, it is not temporary and is not deleted automatically. string rfile = m_outputFile; if (rfile.empty()) { rfile = GetTmpFileName(); received_file_deleter.m_fileName = rfile; } cmd += "-o " + rfile + strings::to_string(" ") + "'" + m_urlRequested + "'"; LOG(LDEBUG, ("Executing", cmd)); try { m_errorCode = stoi(RunCurl(cmd)); } catch (RootException const & ex) { LOG(LERROR, (ex.Msg())); return false; } m_headers.clear(); Headers const headers = ParseHeaders(ReadFileAsString(headers_deleter.m_fileName)); string serverCookies; string headerKey; for (auto const & header : headers) { if (header.first == "Set-Cookie") { serverCookies += header.second + ", "; } else { if (header.first == "Location") m_urlReceived = header.second; if (m_loadHeaders) { headerKey = header.first; strings::AsciiToLower(headerKey); m_headers.emplace(headerKey, header.second); } } } m_headers.emplace("Set-Cookie", NormalizeServerCookies(move(serverCookies))); if (m_urlReceived.empty()) { m_urlReceived = m_urlRequested; // Load body contents in final request only (skip redirects). // Sometimes server can reply with empty body, and it's ok. if (m_outputFile.empty()) m_serverResponse = ReadFileAsString(rfile); } else { // Handle HTTP redirect. // TODO(AlexZ): Should we check HTTP redirect code here? LOG(LDEBUG, ("HTTP redirect", m_errorCode, "to", m_urlReceived)); HttpClient redirect(m_urlReceived); redirect.SetCookies(CombinedCookies()); if (!redirect.RunHttpRequest()) { m_errorCode = -1; return false; } m_errorCode = redirect.ErrorCode(); m_urlReceived = redirect.UrlReceived(); m_headers = move(redirect.m_headers); m_serverResponse = move(redirect.m_serverResponse); } return true; }
// -------------------------------------------------------------------------- // // Function // Name: HTTPRequest::Receive(IOStreamGetLine &, int) // Purpose: Read the request from an IOStreamGetLine (and // attached stream). // Returns false if there was no valid request, // probably due to a kept-alive connection closing. // Created: 26/3/04 // // -------------------------------------------------------------------------- bool HTTPRequest::Receive(IOStreamGetLine &rGetLine, int Timeout) { // Check caller's logic if(mMethod != Method_UNINITIALISED) { THROW_EXCEPTION(HTTPException, RequestAlreadyBeenRead); } // Read the first line, which is of a different format to the rest of the lines std::string requestLine; if(!rGetLine.GetLine(requestLine, false /* no preprocessing */, Timeout)) { // Didn't get the request line, probably end of connection which had been kept alive return false; } BOX_TRACE("Request line: " << requestLine); // Check the method size_t p = 0; // current position in string p = requestLine.find(' '); // end of first word if(p == std::string::npos) { // No terminating space, looks bad p = requestLine.size(); } else { mHttpVerb = requestLine.substr(0, p); if (mHttpVerb == "GET") { mMethod = Method_GET; } else if (mHttpVerb == "HEAD") { mMethod = Method_HEAD; } else if (mHttpVerb == "POST") { mMethod = Method_POST; } else if (mHttpVerb == "PUT") { mMethod = Method_PUT; } else { mMethod = Method_UNKNOWN; } } // Skip spaces to find URI const char *requestLinePtr = requestLine.c_str(); while(requestLinePtr[p] != '\0' && requestLinePtr[p] == ' ') { ++p; } // Check there's a URI following... if(requestLinePtr[p] == '\0') { // Didn't get the request line, probably end of connection which had been kept alive return false; } // Read the URI, unescaping any %XX hex codes while(requestLinePtr[p] != ' ' && requestLinePtr[p] != '\0') { // End of URI, on to query string? if(requestLinePtr[p] == '?') { // Put the rest into the query string, without escaping anything ++p; while(requestLinePtr[p] != ' ' && requestLinePtr[p] != '\0') { mQueryString += requestLinePtr[p]; ++p; } break; } // Needs unescaping? else if(requestLinePtr[p] == '+') { mRequestURI += ' '; } else if(requestLinePtr[p] == '%') { // Be tolerant about this... bad things are silently accepted, // rather than throwing an error. char code[4] = {0,0,0,0}; code[0] = requestLinePtr[++p]; if(code[0] != '\0') { code[1] = requestLinePtr[++p]; } // Convert into a char code long c = ::strtol(code, NULL, 16); // Accept it? if(c > 0 && c <= 255) { mRequestURI += (char)c; } } else { // Simple copy of character mRequestURI += requestLinePtr[p]; } ++p; } // End of URL? if(requestLinePtr[p] == '\0') { // Assume HTTP 0.9 mHTTPVersion = HTTPVersion_0_9; } else { // Skip any more spaces while(requestLinePtr[p] != '\0' && requestLinePtr[p] == ' ') { ++p; } // Check to see if there's the right string next... if(::strncmp(requestLinePtr + p, "HTTP/", 5) == 0) { // Find the version numbers int major, minor; if(::sscanf(requestLinePtr + p + 5, "%d.%d", &major, &minor) != 2) { THROW_EXCEPTION_MESSAGE(HTTPException, BadRequest, "Unable to parse HTTP version number: " << requestLinePtr); } // Store version mHTTPVersion = (major * HTTPVersion__MajorMultiplier) + minor; } else { // Not good -- wrong string found THROW_EXCEPTION_MESSAGE(HTTPException, BadRequest, "Unable to parse HTTP request line: " << requestLinePtr); } } BOX_TRACE("HTTPRequest: method=" << mMethod << ", uri=" << mRequestURI << ", version=" << mHTTPVersion); // If HTTP 1.1 or greater, assume keep-alive if(mHTTPVersion >= HTTPVersion_1_1) { mClientKeepAliveRequested = true; } // Decode query string? if((mMethod == Method_GET || mMethod == Method_HEAD) && !mQueryString.empty()) { HTTPQueryDecoder decoder(mQuery); decoder.DecodeChunk(mQueryString.c_str(), mQueryString.size()); decoder.Finish(); } // Now parse the headers ParseHeaders(rGetLine, Timeout); std::string expected; if(GetHeader("Expect", &expected)) { if(expected == "100-continue") { mExpectContinue = true; } } // Parse form data? if(mMethod == Method_POST && mContentLength >= 0) { // Too long? Don't allow people to be nasty by sending lots of data if(mContentLength > MAX_CONTENT_SIZE) { THROW_EXCEPTION(HTTPException, POSTContentTooLong); } // Some data in the request to follow, parsing it bit by bit HTTPQueryDecoder decoder(mQuery); // Don't forget any data left in the GetLine object int fromBuffer = rGetLine.GetSizeOfBufferedData(); if(fromBuffer > mContentLength) fromBuffer = mContentLength; if(fromBuffer > 0) { BOX_TRACE("Decoding " << fromBuffer << " bytes of " "data from getline buffer"); decoder.DecodeChunk((const char *)rGetLine.GetBufferedData(), fromBuffer); // And tell the getline object to ignore the data we just used rGetLine.IgnoreBufferedData(fromBuffer); } // Then read any more data, as required int bytesToGo = mContentLength - fromBuffer; while(bytesToGo > 0) { char buf[4096]; int toRead = sizeof(buf); if(toRead > bytesToGo) toRead = bytesToGo; IOStream &rstream(rGetLine.GetUnderlyingStream()); int r = rstream.Read(buf, toRead, Timeout); if(r == 0) { // Timeout, just error THROW_EXCEPTION_MESSAGE(HTTPException, RequestReadFailed, "Failed to read complete request with the timeout"); } decoder.DecodeChunk(buf, r); bytesToGo -= r; } // Finish off decoder.Finish(); } else if (mContentLength > 0) { IOStream::pos_type bytesToCopy = rGetLine.GetSizeOfBufferedData(); if (bytesToCopy > mContentLength) { bytesToCopy = mContentLength; } Write(rGetLine.GetBufferedData(), bytesToCopy); SetForReading(); mpStreamToReadFrom = &(rGetLine.GetUnderlyingStream()); } return true; }