void ClientImpl::send(bool finished) { if(_hstate == Idle || _hstate == OnRequestComplete) { // NOTE: might want to handle connect here in the future _hstate = OnRequest; } if(_hstate == OnRequest) { log_debug("begin sending request"); _req.send(finished); log_debug("sent http request completed"); _req.discard(); if( _req.isFinished() ) { ++_requestCount; _hstate = OnRequestComplete; } return; } log_error("sending HTTP request failed: " << _hstate); throw HttpError("HTTP message pending"); }
void ClientImpl::beginReceive() { log_debug("beginReceive: " << _hstate); if(_hstate == Idle) { // NOTE: might want to handle connect here in the future _hstate = OnRequest; } if(_hstate == OnRequest) { log_debug("begin sending cached request"); ///_req.finish(); _hstate = OnRequestEnd; } if(_hstate == OnRequestEnd) { log_debug("flushing cached request"); _req.beginSend(true); return; } if(_hstate == OnReply || _hstate == OnRequestComplete || _hstate == OnReplyComplete) { _hstate = OnReply; _reply.beginReceive(); return; } throw HttpError("HTTP message pending"); }
MessageProgress ClientImpl::endSend() { log_trace("endSend: " << _hstate); if(_hstate == OnRequest) { log_debug("sent http request"); MessageProgress progress = _req.endSend(); if( progress.finished() ) { log_debug("sent http request completed"); _req.discard(); if( _req.isFinished() ) { ++_requestCount; _hstate = OnRequestComplete; _reply.clear(); // TODO: find better place to clear reply !!! } } return progress; } throw HttpError("HTTP message pending"); return MessageProgress(); }
std::istream& ClientImpl::receive() { if(_hstate == Idle) { // NOTE: might want to handle connect here in the future _hstate = OnRequest; } if(_hstate == OnRequest) { log_debug("begin sending cached request"); _hstate = OnRequestEnd; } if(_hstate == OnRequestEnd) { log_debug("flushing cached request"); _req.send(true); log_debug("request completed"); _hstate = OnReply; ++_requestCount; _req.discard(); } if(_hstate == OnReply || _hstate == OnRequestComplete || _hstate == OnReplyComplete) { _hstate = OnReply; _reply.clear(); _reply.receive(); log_debug("reply completed"); assert(0 != _requestCount); if( 0 == --_requestCount) _hstate = Idle; else _hstate = OnReplyComplete; if( ! _conn.isConnected() ) { log_debug("connection closed"); // connection will reconnect automatically } return _reply.body(); } throw HttpError("HTTP message pending"); return _reply.body(); }
MessageProgress ClientImpl::endReceive() { log_debug("endReceive: " << _hstate); if(_hstate == OnRequestEnd) { log_debug("flushed cached request"); MessageProgress progress = _req.endSend(); if( progress.finished() ) { log_debug("request completed"); _req.discard(); _hstate = OnReply; ++_requestCount; _reply.clear(); // TODO: find better place to clear reply !!! } return MessageProgress(); } if(_hstate == OnReply) { log_debug("receiving header"); MessageProgress progress = _reply.endReceive(); if( progress.finished() ) { log_debug("reply completed"); assert(0 != _requestCount); if( 0 == --_requestCount) _hstate = Idle; else _hstate = OnReplyComplete; if( ! _conn.isConnected() ) { log_debug("connection closed"); // connection will reconnect automatically } } return progress; } throw HttpError("HTTP message pending"); return MessageProgress(); }
void ClientImpl::beginSend(bool finished) { log_trace("beginSend: " << _hstate); if(_hstate == Idle || _hstate == OnRequestComplete) { // NOTE: might want to handle connect here in the future _hstate = OnRequest; } if(_hstate == OnRequest) { log_debug("begin sending http chunk"); _req.beginSend(finished); return; } log_error("sending HTTP request failed: " << _hstate); throw HttpError("HTTP message pending"); }
void MessageHeader::add(const char* key, const char* value) { log_debug("MessageHeader::add(\"" << key << "\", \"" << value << "\", " << replace << ')'); if( ! *key) throw std::invalid_argument("header key is NULL"); char* p = eptr(); std::size_t lk = std::strlen(key); // length of key std::size_t lv = std::strlen(value); // length of value if (p - _rawdata + lk + lv + 2 > MaxHeaderSize) throw HttpError("message header too big"); std::strcpy(p, key); // copy key p += lk + 1; std::strcpy(p, value); // copy value p[lv + 1] = '\0'; // put new message end marker in place _endOffset = (p + lv + 1) - _rawdata; }
HttpRequestMessage::HttpRequestMessage(const std::string &buffer) { HttpRequestPart current = HttpRequestPart_Start; std::stringstream stream(buffer); std::string line; // Basic HTTP parser. This needs a LOT of refactoring. while (std::getline(stream, line, '\n')) { if (line.size() && line[line.size() - 1] == '\r') { line = line.substr(0, line.size() - 1); } switch (current) { case HttpRequestPart_Start: { auto remaining = line; // Get method auto split = remaining.find_first_of(" "); if (split == std::string::npos) { throw HttpError(Http::StatusCode_BadRequest, "Malformed begin request line, can't find method: '" + line + "'"); } this->_method = remaining.substr(0, split); remaining = remaining.substr(split + 1); // Get path split = remaining.find_first_of(" "); if (split == std::string::npos) { throw HttpError(Http::StatusCode_BadRequest, "Malformed begin request line, can't find path: '" + line + "'"); } this->_path = remaining.substr(0, split); remaining = remaining.substr(split + 1); // Get split = remaining.find_first_of("/"); if (split == std::string::npos) { throw HttpError(Http::StatusCode_BadRequest, "Malformed begin request line, can't parse HTTP version: '" + line + "'"); } auto http = remaining.substr(0, split); if (http != "HTTP") { throw HttpError(Http::StatusCode_BadRequest, "Malformed begin request line, missing HTTP from header: '" + line + "'"); } auto version = remaining.substr(split + 1); this->_httpVersion = version; current = HttpRequestPart_Headers; } break; case HttpRequestPart_Headers: { bool whiteSpacesOnly = std::all_of(line.begin(), line.end(), isspace); if (whiteSpacesOnly) { current = HttpRequestPart_Body; } else { auto split = line.find_first_of(": "); if (split == std::string::npos) { throw HttpError(Http::StatusCode_BadRequest, "Malformed header line: '" + line + "'"); } auto key = line.substr(0, split); auto value = line.substr(split + 2); this->_headers[key] = value; } } break; case HttpRequestPart_Body: { if (this->_body.size() > 0) { this->_body += "\n"; } this->_body += line; } break; } } }
void CIVConnection::GetHTTPData(LPCTSTR szQuery, CString &rstr) { TRACE (_T("HTTP Request: %s\n"), szQuery); DWORD dwServiceType = 0; CString strServer; CString strObject; INTERNET_PORT nPort=0; bool bFirst = false; HINTERNET hFile = NULL; bool bFailed = false; try { while(1) { if(!m_strHeader.GetLength()) hFile = ::InternetOpenUrl (m_hSession, szQuery, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0 ); else hFile = ::InternetOpenUrl (m_hSession, szQuery, (LPCSTR)m_strHeader, m_strHeader.GetLength(), INTERNET_FLAG_DONT_CACHE, 0 ); if (! hFile) AfxThrowInternetException(0); rstr.Empty(); const int nSizeBuffer = 1024; BYTE pBuffer [nSizeBuffer]; DWORD dwTotalRead = 0; while (true) { DWORD dwRead = 0; BOOL bResult = ::InternetReadFile (hFile, pBuffer, nSizeBuffer, &dwRead); if (! bResult) AfxThrowInternetException(0); if (dwRead ==0) break; DWORD dwOldTotal = dwTotalRead; dwTotalRead += dwRead; LPTSTR szTarget = rstr.GetBuffer(dwTotalRead); szTarget += dwOldTotal; #ifndef _UNICODE memcpy (szTarget, pBuffer, dwRead); #else MultiByteToWideChar (CP_ACP, 0, (LPCSTR) pBuffer, dwRead, szTarget, dwRead); #endif //_UNICODE rstr.ReleaseBuffer(dwTotalRead); } if ( CheckErrorMessage(rstr) ) bFailed = true; else { DWORD dwStatus = QueryInfoStatusCode(hFile); if(HTTP_STATUS_PROXY_AUTH_REQ == dwStatus && !bFirst && m_opts.m_iProxyAuth) { bFirst = true; CString strIn; CString strOut; unsigned nLen = 0; strIn.Format(_T("%s:%s"), (LPCTSTR)m_opts.m_strProxyLogin, (LPCTSTR)m_opts.m_strProxyPassword); encode64((LPCSTR)strIn, strIn.GetLength(), strOut.GetBufferSetLength(200), 190, &nLen); strOut.ReleaseBuffer(); m_strHeader.Format(_T("Proxy-Authorization: Basic %s\r\n"),(LPCTSTR)strOut); InternetCloseHandle(hFile); continue; } if(!m_opts.m_iProxyAuth) m_strHeader = _T(""); if ( HttpError (hFile, dwStatus) ) bFailed = true; } break; } } catch (CInternetException * e ) { bFailed = true; if ( e->m_dwError != ERROR_INTERNET_OPERATION_CANCELLED && e->m_dwError != ERROR_INVALID_HANDLE ) { TCHAR szError [512] = _T("") ; e->GetErrorMessage(szError, sizeof (szError) / sizeof (TCHAR) ); SetError (GetCommonIVError(szError)); } else TRACE (_T("CIVConnection - canceled\n")); e->Delete(); } TRACE (_T("End of HTTP request\n")); if (hFile) ::InternetCloseHandle (hFile); if (bFailed) AfxThrowUserException(); }
HttpErrorHandler::HttpError HttpErrorHandler::getError(const string& no) const{ for(int i = 0;i < HTTP_ERRORS_KNOWN;i++) if(errInfo[i].no == no) return HttpError(i); throw Exception(string("Invalid err no: ") + no); }
void Worker::dispatch(HttpRequest& request, HttpReply& reply) { state = stateDispatch; const std::string& url = request.getUrl(); if (!HttpRequest::checkUrl(url)) { log_info("illegal url <" << url << '>'); throw HttpError(HTTP_BAD_REQUEST, "illegal url"); } request.setThreadContext(this); Dispatcher::PosType pos(application.getDispatcher(), request); while (true) { state = stateDispatch; // pos.getNext() throws NotFoundException at end Maptarget ci = pos.getNext(); try { Component* comp = 0; try { if (ci.libname == application.getAppName()) { // if the libname is the app name look first, if the component is // linked directly try { Compident cii = ci; cii.libname = std::string(); comp = &comploader.fetchComp(cii, application.getDispatcher()); } catch (const NotFoundException&) { // if the component is not found in the binary, fetchComp throws // NotFoundException and comp remains 0. // so we can ignore the exceptioni and just continue } } if (comp == 0) comp = &comploader.fetchComp(ci, application.getDispatcher()); } catch (const NotFoundException& e) { log_debug("NotFoundException catched - url " << e.getUrl() << " try next mapping"); continue; } request.setPathInfo(ci.hasPathInfo() ? ci.getPathInfo() : url); request.setArgs(ci.getArgs()); std::string appname = application.getAppName().empty() ? ci.libname : application.getAppName(); application.getScopemanager().preCall(request, appname); state = stateProcessingRequest; unsigned http_return; const char* http_msg; std::string msg; try { http_return = comp->topCall(request, reply, request.getQueryParams()); http_msg = HttpReturn::httpMessage(http_return); } catch (const HttpReturn& e) { http_return = e.getReturnCode(); msg = e.getMessage(); http_msg = msg.c_str(); } if (http_return != DECLINED) { if (reply.isDirectMode()) { log_info("request " << request.getMethod_cstr() << ' ' << request.getQuery() << " ready, returncode " << http_return << ' ' << http_msg); state = stateFlush; reply.out().flush(); } else { log_info("request " << request.getMethod_cstr() << ' ' << request.getQuery() << " ready, returncode " << http_return << ' ' << http_msg << " - ContentSize: " << reply.getContentSize()); application.getScopemanager().postCall(request, reply, appname); state = stateSendReply; reply.sendReply(http_return, http_msg); } logRequest(request, reply, http_return); if (reply.out()) log_debug("reply sent"); else { reply.setKeepAliveCounter(0); log_warn("sending failed"); } return; } else log_debug("component " << ci << " returned DECLINED"); } catch (const LibraryNotFound& e) { log_warn("library " << e.getLibname() << " not found"); } } throw NotFoundException(request.getUrl()); }
bool Worker::processRequest(HttpRequest& request, std::iostream& socket, unsigned keepAliveCount) { // log message log_info("request " << request.getMethod_cstr() << ' ' << request.getQuery() << " from client " << request.getPeerIp() << " user-Agent \"" << request.getUserAgent() << "\" user \"" << request.getUsername() << '"'); // create reply-object HttpReply reply(socket); reply.setVersion(request.getMajorVersion(), request.getMinorVersion()); if (request.isMethodHEAD()) reply.setHeadRequest(); #ifdef ENABLE_LOCALE reply.setLocale(request.getLocale()); #endif if (request.keepAlive()) reply.setKeepAliveCounter(keepAliveCount); if (TntConfig::it().enableCompression) reply.setAcceptEncoding(request.getEncoding()); // process request try { try { dispatch(request, reply); if (!request.keepAlive() || !reply.keepAlive()) keepAliveCount = 0; if (keepAliveCount > 0) log_debug("keep alive"); else { log_debug("no keep alive request/reply=" << request.keepAlive() << '/' << reply.keepAlive()); } } catch (const HttpError& e) { throw; } catch (const std::exception& e) { throw HttpError(HTTP_INTERNAL_SERVER_ERROR, e.what()); } catch (...) { log_error("unknown exception"); throw HttpError(HTTP_INTERNAL_SERVER_ERROR, "unknown error"); } } catch (const HttpError& e) { state = stateSendError; log_warn("http-Error: " << e.what()); HttpReply errorReply(socket); errorReply.setVersion(request.getMajorVersion(), request.getMinorVersion()); if (request.keepAlive()) errorReply.setKeepAliveCounter(keepAliveCount); else keepAliveCount = 0; for (HttpMessage::header_type::const_iterator it = e.header_begin(); it != e.header_end(); ++it) errorReply.setHeader(it->first, it->second); errorReply.out() << e.getBody() << '\n'; errorReply.sendReply(e.getErrcode(), e.getErrmsg()); logRequest(request, errorReply, e.getErrcode()); } return keepAliveCount > 0; }