void WEnvironment::enableAjax(const WebRequest& request) { doesAjax_ = true; session_->controller()->newAjaxSession(); doesCookies_ = !request.headerValue("Cookie").empty(); if (!request.getParameter("htmlHistory")) hashInternalPaths_ = true; const std::string *scaleE = request.getParameter("scale"); try { dpiScale_ = scaleE ? boost::lexical_cast<double>(*scaleE) : 1; } catch (boost::bad_lexical_cast &e) { dpiScale_ = 1; } const std::string *hashE = request.getParameter("_"); // the internal path, when present as an anchor (#), is only // conveyed in the second request if (hashE) setInternalPath(*hashE); const std::string *deployPathE = request.getParameter("deployPath"); if (deployPathE) { publicDeploymentPath_ = *deployPathE; std::size_t s = publicDeploymentPath_.find('/'); if (s != 0) publicDeploymentPath_.clear(); // looks invalid } }
void WEnvironment::enableAjax(const WebRequest& request) { doesAjax_ = true; session_->controller()->newAjaxSession(); doesCookies_ = request.headerValue("Cookie") != 0; if (!request.getParameter("htmlHistory")) hashInternalPaths_ = true; const std::string *scaleE = request.getParameter("scale"); try { dpiScale_ = scaleE ? boost::lexical_cast<double>(*scaleE) : 1; } catch (boost::bad_lexical_cast &e) { dpiScale_ = 1; } const std::string *webGLE = request.getParameter("webGL"); webGLsupported_ = webGLE ? (*webGLE == "true") : false; const std::string *tzE = request.getParameter("tz"); try { timeZoneOffset_ = tzE ? boost::lexical_cast<int>(*tzE) : 0; } catch (boost::bad_lexical_cast &e) { } const std::string *hashE = request.getParameter("_"); // the internal path, when present as an anchor (#), is only // conveyed in the second request if (hashE) setInternalPath(*hashE); const std::string *deployPathE = request.getParameter("deployPath"); if (deployPathE) { publicDeploymentPath_ = *deployPathE; std::size_t s = publicDeploymentPath_.find('/'); if (s != 0) publicDeploymentPath_.clear(); // looks invalid } const std::string *scrWE = request.getParameter("scrW"); if (scrWE) { try { screenWidth_ = boost::lexical_cast<int>(*scrWE); } catch (boost::bad_lexical_cast &) { } } const std::string *scrHE = request.getParameter("scrH"); if (scrHE) { try { screenHeight_ = boost::lexical_cast<int>(*scrHE); } catch (boost::bad_lexical_cast &) { } } }
/* * Read until finding the boundary, saving to resultString or * resultFile. The boundary itself is not consumed. * * tossAtBoundary controls how many characters extra (<0) * or few (>0) are saved at the start of the boundary in the result. */ void CgiParser::readUntilBoundary(WebRequest& request, const std::string boundary, int tossAtBoundary, std::string *resultString, std::ostream *resultFile) { int bpos; while ((bpos = index(boundary)) == -1) { /* * If we couldn't find it. We need to wind the buffer, but only save * not including the boundary length. */ if (left_ == 0) throw WException("CgiParser: reached end of input while seeking end of " "headers or content. Format of CGI input is wrong"); /* save (up to) BUFSIZE from buffer to file or value string, but * mind the boundary length */ int save = std::min((buflen_ - (int)boundary.length()), (int)BUFSIZE); if (save > 0) { if (resultString) *resultString += std::string(buf_, save); if (resultFile) resultFile->write(buf_, save); /* wind buffer */ windBuffer(save); } unsigned amt = static_cast<unsigned> (std::min(left_, static_cast< ::int64_t >(BUFSIZE + MAXBOUND - buflen_))); request.in().read(buf_ + buflen_, amt); if (request.in().gcount() != (int)amt) throw WException("CgiParser: short read"); left_ -= amt; buflen_ += amt; } if (resultString) *resultString += std::string(buf_, bpos - tossAtBoundary); if (resultFile) resultFile->write(buf_, bpos - tossAtBoundary); /* wind buffer */ windBuffer(bpos); }
void WebSocket::on_readable (void) { int err; int index; WebRequest *request; if (read_buffer_size - read_buffer_len < BUFFER_SIZE) { read_buffer_size += BUFFER_SIZE; read_buffer = (char *) realloc (read_buffer, read_buffer_size); } err = recv (sockfd, &read_buffer[read_buffer_len], read_buffer_size - read_buffer_len, 0); log (LOG_WEBSOCKET, "WebSocket::on_readable (%d)", err); if (err < 0) { log (LOG_ERROR, "recv (%d : %s)", errno, strerror (errno)); return; } if (err == 0) { this->set_delete_pending (); this->set_delete_ready (); return; } read_buffer_len += err; // err is actually the length of data read for (index = 3; index < read_buffer_len; index ++) { if ( (read_buffer[index - 3] == 0x0D) && (read_buffer[index - 2] == 0x0A) && (read_buffer[index - 1] == 0x0D) && (read_buffer[index - 0] == 0x0A) ) { read_buffer[index - 3] = 0; request = new WebRequest (this, read_buffer); request->process (); delete request; } } }
std::string WEnvironment::getClientAddress(const WebRequest& request, const Configuration& conf) { std::string result; /* * Determine client address, taking into account proxies */ if (conf.behindReverseProxy()) { std::string clientIp = request.headerValue("Client-IP"); boost::trim(clientIp); std::vector<std::string> ips; if (!clientIp.empty()) boost::split(ips, clientIp, boost::is_any_of(",")); std::string forwardedFor = request.headerValue("X-Forwarded-For"); boost::trim(forwardedFor); std::vector<std::string> forwardedIps; if (!forwardedFor.empty()) boost::split(forwardedIps, forwardedFor, boost::is_any_of(",")); Utils::insert(ips, forwardedIps); for (unsigned i = 0; i < ips.size(); ++i) { result = ips[i]; boost::trim(result); if (!result.empty() && !boost::starts_with(result, "10.") && !boost::starts_with(result, "172.16.") && !boost::starts_with(result, "192.168.")) { break; } } } if (result.empty()) result = request.envValue("REMOTE_ADDR"); return result; }
//Test HTTP Get Request void TestHttpGet(){ //Initialize Web Request Manager WebRequest *webRequest = new WebRequest(); //Execute Get Request tcp::iostream *stream = webRequest->HttpGet("www.google.com", "/"); //Console message cout << "----------------------------------\r\n"; //Console message cout << "HTTP Response data:\r\n"; //Response data cout << stream->rdbuf(); //Destroy stream object delete stream; //Destroy web request object delete webRequest; }
//Test HTTP Post Request void TestHttpPost(){ //Initialize Web Request Manager WebRequest *webRequest = new WebRequest(); //Data to send char data[] = "Testing Post Method"; //Execute Post Request tcp::iostream *stream = webRequest->HttpPost("requestb.in", "/st92m7st", data, 19); //Console message cout << "----------------------------------\r\n"; //Console message cout << "HTTP Response data:\r\n"; //Response data cout << stream->rdbuf(); //Destroy stream object delete stream; //Destroy web request object delete webRequest; }
void JavaScriptEvent::get(const WebRequest& request, const std::string& se) { std::string s = se; int seLength = se.length(); type = getStringParameter(request, concat(s, seLength, "type")); boost::to_lower(type); clientX = parseIntParameter(request, concat(s, seLength, "clientX"), 0); clientY = parseIntParameter(request, concat(s, seLength, "clientY"), 0); documentX = parseIntParameter(request, concat(s, seLength, "documentX"), 0); documentY = parseIntParameter(request, concat(s, seLength, "documentY"), 0); screenX = parseIntParameter(request, concat(s, seLength, "screenX"), 0); screenY = parseIntParameter(request, concat(s, seLength, "screenY"), 0); widgetX = parseIntParameter(request, concat(s, seLength, "widgetX"), 0); widgetY = parseIntParameter(request, concat(s, seLength, "widgetY"), 0); dragDX = parseIntParameter(request, concat(s, seLength, "dragdX"), 0); dragDY = parseIntParameter(request, concat(s, seLength, "dragdY"), 0); wheelDelta = parseIntParameter(request, concat(s, seLength, "wheel"), 0); /* if (widgetX == 0 && widgetY == 0) { const int signalLength = 7 + se.length(); const Http::ParameterMap& entries = request.getParameterMap(); for (Http::ParameterMap::const_iterator i = entries.begin(); i != entries.end(); ++i) { std::string name = i->first; if (name.substr(0, signalLength) == concat(s, seLength, "signal=") { std::string e = name.substr(name.length() - 2); if (e == ".x") { try { widgetX = boost::lexical_cast<int>(i->second[0]); } catch (const boost::bad_lexical_cast& ee) { } } else if (e == ".y") { try { widgetY = boost::lexical_cast<int>(i->second[0]); } catch (const boost::bad_lexical_cast& ee) { } } } } } */ modifiers = 0; if (request.getParameter(concat(s, seLength, "altKey")) != 0) modifiers |= AltModifier; if (request.getParameter(concat(s, seLength, "ctrlKey")) != 0) modifiers |= ControlModifier; if (request.getParameter(concat(s, seLength, "shiftKey")) != 0) modifiers |= ShiftModifier; if (request.getParameter(concat(s, seLength, "metaKey")) != 0) modifiers |= MetaModifier; keyCode = parseIntParameter(request, concat(s, seLength, "keyCode"), 0); charCode = parseIntParameter(request, concat(s, seLength, "charCode"), 0); button = parseIntParameter(request, concat(s, seLength, "button"), 0); scrollX = parseIntParameter(request, concat(s, seLength, "scrollX"), 0); scrollY = parseIntParameter(request, concat(s, seLength, "scrollY"), 0); viewportWidth = parseIntParameter(request, concat(s, seLength, "width"), 0); viewportHeight = parseIntParameter(request, concat(s, seLength, "height"), 0); response = getStringParameter(request, concat(s, seLength, "response")); int uean = parseIntParameter(request, concat(s, seLength, "an"), 0); userEventArgs.clear(); for (int i = 0; i < uean; ++i) { userEventArgs.push_back (getStringParameter(request, se + "a" + boost::lexical_cast<std::string>(i))); } decodeTouches(getStringParameter(request, concat(s, seLength, "touches")), touches); decodeTouches(getStringParameter(request, concat(s, seLength, "ttouches")), targetTouches); decodeTouches(getStringParameter(request, concat(s, seLength, "ctouches")), changedTouches); }
void WebConnection::_connectionLoop() { uint32_t buffersize = 0; unsigned char* buffer = NULL; uint32_t readpos = 0; for (;;) { if (READ_SIZE + readpos > buffersize) { buffersize += READ_SIZE; buffer = (unsigned char*)realloc(buffer, buffersize); } int32_t read = _socket->Receive(&buffer[readpos], READ_SIZE); if (read <= 0) break; readpos += read; unsigned char* contentStart; unsigned char* headerStart = buffer; if ((contentStart = (unsigned char*)memmem(buffer, readpos, "\r\n\r\n", 4)) != NULL) { // Find request end contentStart += 4; uint32_t headerLength = _convertNewLines(buffer, contentStart - headerStart); log_data(LOG_INFO, (char*)buffer, headerLength - 1); char* cmd = (char*) headerStart; char* path = NULL; char* protocol = NULL; while (headerStart[0] != '\n') { if (headerStart[0] == ' ') { if (path == NULL) path = (char*)&headerStart[1]; else if (protocol == NULL) protocol = (char*)&headerStart[1]; headerStart[0] = '\0'; } headerStart++; headerLength--; } headerStart[0] = '\0'; headerStart++; headerLength--; WebRequest* request = new WebRequest(cmd, path, protocol); request->getHeaders()->_parseHeaders((char*)headerStart, contentStart - headerStart); const char* contentLengthStr; unsigned char* content = NULL; uint32_t contentLength = 0; if ((contentLengthStr = request->getHeaders()->valueForName("Content-Length")) != NULL && (contentLength = atoi(contentLengthStr)) > 0) { content = (unsigned char*) malloc(contentLength); uint32_t contentReadPos = readpos - (contentStart - buffer); memcpy(content, contentStart, contentReadPos); while (contentReadPos < contentLength) { int32_t contentRead = _socket->Receive(&content[contentReadPos], contentLength - contentReadPos); if (contentRead < 0) { log(LOG_ERROR, "Connection read error"); break; } contentReadPos += contentRead; } log(LOG_INFO, "(Content of length: %d bytes)\n", contentLength); } assert(_processRequestCallback != NULL); if (contentLength > 0 && content != NULL) request->_setContent(content, contentLength); _processRequestCallback(this, request, _callbackCtx); assert(request->_response->_statusCode < 1000); if (request->_response->_statusCode == 404 && request->_response->_headers->_headerCount == 0) request->_response->_headers->addValue("Content-Length", "0"); if (request->_response->_contentLength > 0) request->_response->_headers->addValue("Content-Length", "%d", request->_response->_contentLength); uint32_t protocolLen = strlen(request->getProtocol()); uint32_t statusCodeLen = 3; uint32_t statusMessageLen = strlen(request->_response->_statusMessage); uint32_t statusLineLen = protocolLen + 1 + statusCodeLen + 1 + statusMessageLen + 2; uint32_t headersLen = request->_response->_headers->getTotalLength(); uint32_t totalLen = statusLineLen + headersLen; char* res = (char*)malloc(totalLen); snprintf(res, totalLen, "%s %d %s\r\n", request->getProtocol(), request->_response->_statusCode, request->_response->_statusMessage); request->_response->_headers->getContent(&res[statusLineLen], totalLen - statusLineLen); log_data(LOG_INFO, res, totalLen); _socket->Send(res, totalLen); free(res); if (request->_response->_contentLength > 0) { log_data(LOG_INFO, (char*) request->_response->_content, request->_response->_contentLength); _socket->Send((char*)request->_response->_content, request->_response->_contentLength); } if (!request->_response->_keepAlive) _socket->Close(); delete request; if (content != NULL) free(content); } free(buffer); buffer = NULL; buffersize = 0; readpos = 0; } log(LOG_INFO, "Client disconnected"); _socket->Close(); if (buffer != NULL) free(buffer); _mutex.lock(); _isConnected = false; _mutex.unlock(); _server->_connectionClosed(this); if (_connectionClosedCallback != NULL) _connectionClosedCallback(this, _callbackCtx); if (_shouldSelfDestroy) delete this; }
void CgiParser::parse(WebRequest& request, ReadOption readOption) { /* * TODO: optimize this ... */ request_ = &request; ::int64_t len = request.contentLength(); std::string type = request.contentType(); std::string meth = request.requestMethod(); request.postDataExceeded_ = (len > maxPostData_ ? len : 0); std::string queryString = request.queryString(); // XDomainRequest cannot set a contentType header, we therefore pass it // as a request parameter if (readOption != ReadHeadersOnly && meth == "POST" && (type.find("application/x-www-form-urlencoded") == 0 || queryString.find("&contentType=x-www-form-urlencoded") != std::string::npos)) { /* * TODO: parse this stream-based to avoid the malloc here. For now * we protect the maximum that can be POST'ed as form data. */ if (len > 5*1024*1024) throw WException("Oversized application/x-www-form-urlencoded (" + boost::lexical_cast<std::string>(len) + ")"); char *buf = new char[len + 1]; request.in().read(buf, len); if (request.in().gcount() != (int)len) { delete[] buf; throw WException("Unexpected short read."); } buf[len] = 0; // This is a special Wt feature, I do not think it standard. // For POST, parameters in url-encoded URL are still parsed. if (!queryString.empty()) queryString += '&'; queryString += buf; delete[] buf; } LOG_DEBUG("queryString (len=" << len << "): " << queryString); if (!queryString.empty()) Http::Request::parseFormUrlEncoded(queryString, request_->parameters_); if (readOption != ReadHeadersOnly && type.find("multipart/form-data") == 0) { if (meth != "POST") { throw WException("Invalid method for multipart/form-data: " + meth); } if (!request.postDataExceeded_) readMultipartData(request, type, len); else if (readOption == ReadBodyAnyway) { for (;len > 0;) { ::int64_t toRead = std::min(::int64_t(BUFSIZE), len); request.in().read(buf_, toRead); if (request.in().gcount() != (::int64_t)toRead) throw WException("CgiParser: short read"); len -= toRead; } } } }
void WEnvironment::init(const WebRequest& request) { Configuration& conf = session_->controller()->configuration(); queryString_ = request.queryString(); parameters_ = request.getParameterMap(); urlScheme_ = request.urlScheme(); referer_ = request.headerValue("Referer"); accept_ = request.headerValue("Accept"); serverSignature_ = request.envValue("SERVER_SIGNATURE"); serverSoftware_ = request.envValue("SERVER_SOFTWARE"); serverAdmin_ = request.envValue("SERVER_ADMIN"); pathInfo_ = request.pathInfo(); #ifndef WT_TARGET_JAVA sslInfo_ = request.sslInfo(); #endif setUserAgent(request.headerValue("User-Agent")); LOG_INFO("UserAgent: " << userAgent_); /* * Determine server host name */ if (conf.behindReverseProxy()) { /* * Take the last entry in X-Forwarded-Host, assuming that we are only * behind 1 proxy */ std::string forwardedHost = request.headerValue("X-Forwarded-Host"); if (!forwardedHost.empty()) { std::string::size_type i = forwardedHost.rfind(','); if (i == std::string::npos) host_ = forwardedHost; else host_ = forwardedHost.substr(i+1); } else host_ = request.headerValue("Host"); } else host_ = request.headerValue("Host"); if (host_.empty()) { /* * HTTP 1.0 doesn't require it: guess from config */ host_ = request.serverName(); if (!request.serverPort().empty()) host_ += ":" + request.serverPort(); } clientAddress_ = getClientAddress(request, conf); std::string cookie = request.headerValue("Cookie"); doesCookies_ = !cookie.empty(); if (doesCookies_) parseCookies(cookie, cookies_); locale_ = request.parseLocale(); }
void WEnvironment::updateUrlScheme(const WebRequest& request) { urlScheme_ = str(request.urlScheme()); Configuration& conf = session_->controller()->configuration(); #ifndef WT_TARGET_JAVA if (conf.behindReverseProxy() || server()->dedicatedSessionProcess()) { #else if (conf.behindReverseProxy()){ #endif std::string forwardedProto = str(request.headerValue("X-Forwarded-Proto")); if (!forwardedProto.empty()) { std::string::size_type i = forwardedProto.rfind(','); if (i == std::string::npos) urlScheme_ = forwardedProto; else urlScheme_ = forwardedProto.substr(i+1); } } } void WEnvironment::init(const WebRequest& request) { Configuration& conf = session_->controller()->configuration(); queryString_ = request.queryString(); parameters_ = request.getParameterMap(); host_ = str(request.headerValue("Host")); referer_ = str(request.headerValue("Referer")); accept_ = str(request.headerValue("Accept")); serverSignature_ = str(request.envValue("SERVER_SIGNATURE")); serverSoftware_ = str(request.envValue("SERVER_SOFTWARE")); serverAdmin_ = str(request.envValue("SERVER_ADMIN")); pathInfo_ = request.pathInfo(); #ifndef WT_TARGET_JAVA if(!str(request.headerValue("Redirect-Secret")).empty()) session_->controller()->redirectSecret_ = str(request.headerValue("Redirect-Secret")); sslInfo_ = request.sslInfo(); if(!sslInfo_ && !str(request.headerValue("SSL-Client-Certificates")).empty()) { parseSSLInfo(str(request.headerValue("SSL-Client-Certificates"))); } #endif setUserAgent(str(request.headerValue("User-Agent"))); updateUrlScheme(request); LOG_INFO("UserAgent: " << userAgent_); /* * If behind a reverse proxy, use external host, schema as communicated using 'X-Forwarded' * headers. */ #ifndef WT_TARGET_JAVA if (conf.behindReverseProxy() || server()->dedicatedSessionProcess()) { #else if (conf.behindReverseProxy()){ #endif std::string forwardedHost = str(request.headerValue("X-Forwarded-Host")); if (!forwardedHost.empty()) { std::string::size_type i = forwardedHost.rfind(','); if (i == std::string::npos) host_ = forwardedHost; else host_ = forwardedHost.substr(i+1); } } if (host_.empty()) { /* * HTTP 1.0 doesn't require it: guess from config */ host_ = request.serverName(); if (!request.serverPort().empty()) host_ += ":" + request.serverPort(); } clientAddress_ = getClientAddress(request, conf); const char *cookie = request.headerValue("Cookie"); doesCookies_ = cookie; if (cookie) parseCookies(cookie, cookies_); locale_ = request.parseLocale(); } #ifndef WT_TARGET_JAVA void WEnvironment::parseSSLInfo(const std::string& json) { #ifdef WT_WITH_SSL Wt::Json::Object obj; Wt::Json::ParseError error; if(!Wt::Json::parse(Wt::Utils::base64Decode(json), obj, error)) { LOG_ERROR("error while parsing client certificates"); return; } std::string clientCertificatePem = obj["client-certificate"]; X509* cert = Wt::Ssl::readFromPem(clientCertificatePem); if(cert) { Wt::WSslCertificate clientCert = Wt::Ssl::x509ToWSslCertificate(cert); X509_free(cert); Wt::Json::Array arr = obj["client-pem-certification-chain"]; std::vector<Wt::WSslCertificate> clientCertChain; for(unsigned int i = 0; i < arr.size(); ++i ) { clientCertChain.push_back(Wt::Ssl::x509ToWSslCertificate(Wt::Ssl::readFromPem(arr[i]))); } Wt::WValidator::State state = static_cast<Wt::WValidator::State>((int)obj["client-verification-result-state"]); Wt::WString message = obj["client-verification-result-message"]; sslInfo_ = new Wt::WSslInfo(clientCert, clientCertChain, Wt::WValidator::Result(state, message)); } #endif // WT_WITH_SSL }
void test_web_request(void) { console->log("Testing webrequest.."); WebRequest r = WebRequest("GET /foo/bar/baz HTTP/1.1"); console->log(r.path); assert(0 == r.path.compare("/foo/bar/")); assert(0 == r.filename.compare("baz")); r = WebRequest("get /jack.css"); assert(0 == r.path.compare("/")); assert(0 == r.filename.compare("jack.css")); r = WebRequest("get /jack.html?foo=bar;baz=bam"); assert(0 == r.path.compare("/")); console->log(r.filename); assert(0 == r.filename.compare("jack.html")); assert(1 == r.has_cgi_params); assert(0 == r.param("foo").compare("bar")); assert(0 == r.param("baz").compare("bam")); assert(0 == r.paramn("jerry")); assert(0 == r.get_uri().compare("/jack.html?foo=bar;baz=bam")); r.param("foo", 2); assert(0 == r.get_uri().compare("/jack.html?foo=2;baz=bam")); WebRequest b = WebRequest(r.get_uri()); console->log(b.get_uri()); assert(0 == b.get_uri().compare("/jack.html?foo=2;baz=bam")); b.delete_param("foo"); assert(0 == b.get_uri().compare("/jack.html?baz=bam")); }
void WEnvironment::enableAjax(const WebRequest& request) { doesAjax_ = true; session_->controller()->newAjaxSession(); doesCookies_ = request.headerValue("Cookie") != nullptr; if (!request.getParameter("htmlHistory")) internalPathUsingFragments_ = true; const std::string *scaleE = request.getParameter("scale"); try { dpiScale_ = scaleE ? Utils::stod(*scaleE) : 1; } catch (std::exception& e) { dpiScale_ = 1; } const std::string *webGLE = request.getParameter("webGL"); webGLsupported_ = webGLE ? (*webGLE == "true") : false; const std::string *tzE = request.getParameter("tz"); try { timeZoneOffset_ = std::chrono::minutes{tzE ? Utils::stoi(*tzE) : 0}; } catch (std::exception& e) { } const std::string *tzSE = request.getParameter("tzS"); timeZoneName_ = tzSE ? *tzSE : std::string(""); const std::string *hashE = request.getParameter("_"); // the internal path, when present as an anchor (#), is only // conveyed in the second request if (hashE) setInternalPath(*hashE); const std::string *deployPathE = request.getParameter("deployPath"); if (deployPathE) { publicDeploymentPath_ = *deployPathE; std::size_t s = publicDeploymentPath_.find('/'); if (s != 0) publicDeploymentPath_.clear(); // looks invalid } const std::string *scrWE = request.getParameter("scrW"); if (scrWE) { try { screenWidth_ = Utils::stoi(*scrWE); } catch (std::exception &e) { } } const std::string *scrHE = request.getParameter("scrH"); if (scrHE) { try { screenHeight_ = Utils::stoi(*scrHE); } catch (std::exception &e) { } } }