void respond(int code, const QByteArray &reason, const HttpHeaders &headers, const QByteArray &body) { if(state != WriteBody) return; HttpHeaders outHeaders = headers; outHeaders.removeAll("Connection"); outHeaders.removeAll("Transfer-Encoding"); outHeaders.removeAll("Content-Length"); outHeaders += HttpHeader("Connection", "close"); outHeaders += HttpHeader("Content-Length", QByteArray::number(body.size())); QByteArray respData = "HTTP/"; if(version1dot0) respData += "1.0 "; else respData += "1.1 "; respData += QByteArray::number(code) + " " + reason + "\r\n"; foreach(const HttpHeader &h, outHeaders) respData += h.first + ": " + h.second + "\r\n"; respData += "\r\n"; respData += body; state = WaitForWritten; pendingWritten += respData.size(); sock->write(respData); }
void checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate) { using namespace base; using namespace net; std::string url = UPDATE_URL; if (!uuid.empty()) { url += "&uuid="; url += uuid; } if (!extraParams.empty()) { url += "&"; url += extraParams; } HttpRequest request(url); HttpHeaders headers; headers.setHeader("User-Agent", getUserAgent()); request.setHeaders(headers); std::stringstream body; HttpResponse response(&body); request.send(response); CheckUpdateResponse data(body.str()); delegate->onResponse(data); }
YETI_Result HttpEntity::set_headers(const HttpHeaders & headers) { HttpHeader * header; header = headers.get_header(YETI_HTTP_HEADER_CONTENT_LENGTH); if (header != NULL) { m_content_length_is_known_ = true; YETI_LargeSize length; if (YETI_SUCCEEDED(header->get_value().to_integer64(length))) { m_content_length_ = length; } else { m_content_length_ = 0; } } header = headers.get_header(YETI_HTTP_HEADER_CONTENT_TYPE); if (header != NULL) { m_content_type_ = header->get_value(); } header = headers.get_header(YETI_HTTP_HEADER_CONTENT_ENCODING); if (header != NULL) { m_content_encoding_ = header->get_value(); } header = headers.get_header(YETI_HTTP_HEADER_TRANSFER_ENCODING); if (header != NULL) { m_transfer_encoding_ = header->get_value(); } return YETI_SUCCESS; }
void checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate) { using namespace base; using namespace net; #ifndef UPDATE_URL #define UPDATE_URL "" #endif #pragma message("warning: Define UPDATE_URL macro") std::string url = UPDATE_URL; if (!uuid.empty()) { url += "&uuid="; url += uuid; } if (!extraParams.empty()) { url += "&"; url += extraParams; } HttpRequest request(url); HttpHeaders headers; headers.setHeader("User-Agent", getUserAgent()); request.setHeaders(headers); std::stringstream body; HttpResponse response(&body); request.send(response); TRACE("Checking updates: %s (User-Agent: %s)\n", url.c_str(), getUserAgent().c_str()); TRACE("Response:\n--\n%s--\n", body.str().c_str()); CheckUpdateResponse data(body.str()); delegate->onResponse(data); }
void setup(const QUrl &_uri, const HttpHeaders &_headers, const QHostAddress &connectAddr = QHostAddress(), int connectPort = -1, int _maxRedirects = -1, const QString &connectHostToTrust = QString()) { assert(!method.isEmpty()); QUrl uri = _uri; if(connectPort != -1) uri.setPort(connectPort); else if(uri.port() == -1) { if(uri.scheme() == "https") uri.setPort(443); else uri.setPort(80); } HttpHeaders headers = _headers; checkHosts += uri.host(QUrl::FullyEncoded); if(!connectAddr.isNull()) { curl_slist_free_all(dnsCache); if(!connectHostToTrust.isEmpty()) checkHosts += connectHostToTrust; QByteArray cacheEntry = uri.host(QUrl::FullyEncoded).toUtf8() + ':' + QByteArray::number(uri.port()) + ':' + connectAddr.toString().toUtf8(); dnsCache = curl_slist_append(dnsCache, cacheEntry.data()); curl_easy_setopt(easy, CURLOPT_RESOLVE, dnsCache); } curl_easy_setopt(easy, CURLOPT_URL, uri.toEncoded().data()); bool chunked = false; if(headers.contains("Content-Length")) { curl_off_t content_len = (curl_off_t)headers.get("Content-Length").toLongLong(); /*if(method == "POST") curl_easy_setopt(easy, CURLOPT_POSTFIELDSIZE_LARGE, content_len); else*/ curl_easy_setopt(easy, CURLOPT_INFILESIZE_LARGE, content_len); // curl will set this for us headers.removeAll("Content-Length"); } else { if(expectBody) chunked = true; else if(alwaysSetBody) curl_easy_setopt(easy, CURLOPT_INFILESIZE_LARGE, (curl_off_t)0); } curl_slist_free_all(headersList); foreach(const HttpHeader &h, headers) { QByteArray i = h.first + ": " + h.second; headersList = curl_slist_append(headersList, i.data()); }
bool HttpContentNegociation::Apply(const HttpHeaders& headers) { HttpHeaders::const_iterator accept = headers.find("accept"); if (accept != headers.end()) { return Apply(accept->second); } else { return Apply("*/*"); } }
void applyHeaders(const HttpHeaders &in, HttpHeaders *out) { *out += HttpHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); QByteArray origin; if(in.contains("Origin")) origin = in.get("Origin"); else origin = "*"; *out += HttpHeader("Access-Control-Allow-Origin", origin); *out += HttpHeader("Access-Control-Allow-Credentials", "true"); }
Response* FakeConnection::getDocument(const std::string& uri) { TIMED_FUNC(FakeConnection_getDocument); LOG(DEBUG) << " Entering FakeConnection::getDocument"; LOG(DEBUG) << " Fetching document with URI: " << uri; std::map<std::string,IDocumentContent*>::iterator it; it = mImpl->documents.find(uri); std::string ct(""); std::string mime(""); if (mImpl->documents.end() != it) { LOG(DEBUG) << " Found document with URI: " << uri; IDocumentContent* docPtr = it->second; ct = docPtr->getContent(); mime = docPtr->getMimeType(); } //IDocumentContent& value = mImpl->documents[uri.c_str()]; //LOG(DEBUG) << " pointer value: " << value; Response* response = new Response; LOG(DEBUG) << " Setting response code"; LOG(DEBUG) << " Setting response content ptr"; //std::unique_ptr<std::string> content(new std::string(ct)); //response->setContent(std::move(content)); response->setContent(new std::string(ct)); LOG(DEBUG) << " Setting response headers"; if (0 == ct.compare("")) { // not found response->setResponseCode(ResponseCode::NOT_FOUND); response->setResponseType(ResponseType::UNKNOWN_TYPE); } else { // found HttpHeaders headers; headers.setHeader("Content-type",mime); response->setResponseHeaders(headers); response->setResponseCode(ResponseCode::OK); if (0 == mime.compare("application/json")) { response->setResponseType(ResponseType::JSON); } else if (0 == mime.compare("application/xml") ) { response->setResponseType(ResponseType::XML); } else if (0 == mime.compare("text/plain")) { response->setResponseType(ResponseType::TEXT); } else { response->setResponseType(ResponseType::BINARY); } } LOG(DEBUG) << " returning response "; return response; }
void Logger::logFromClient(std::string &name, HttpHeaders &headers) { std::string message = "Got POST ("; message.append(name); message.append(") :\n"); message.append(headers.getPostData()); log4cpp::Category::getInstance("sslsniff").info(message); }
void setHeaders(const HttpHeaders& headers) { if (m_headerlist) { curl_slist_free_all(m_headerlist); m_headerlist = NULL; } std::string tmp; for (HttpHeaders::const_iterator it=headers.begin(), end=headers.end(); it!=end; ++it) { tmp = it->first; tmp += ": "; tmp += it->second; m_headerlist = curl_slist_append(m_headerlist, tmp.c_str()); } curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_headerlist); }
/* * This function serves as a callback for response headers read by libcurl * * The libcurl documentation at * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTHEADERFUNCTION * says that the callback is called once for each header and only complete * header line are passed. So we do not need to handle multi-line headers * ourselves. * * Please see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html * The first response header returned will always be "Status-line", * Also see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 */ static size_t headers_callback(void *buffer, size_t size, size_t nmemb, void *userp) { char *buf = reinterpret_cast<char*>(buffer); HttpHeaders *pHeaders = reinterpret_cast<HttpHeaders*>(userp); size_t result = 0u; if (pHeaders != NULL) { /* * Note: std::string is capable of storing binary stream data and can * store "\0" as normal character (witout terminating string). * * - Until C++11, it is not guaranteed to be contiguously stored though. * - Use caution when using .c_str(), if string contains "\0", use .data() instead * * Since binary data can be stored in std::string, unicode characters * can be present But beware of using .length() or .size(), since they * will return number of bytes storage (i.e., char) needed to store the * string, and not actual number of characters. */ std::string s = ""; s.append(buf, size * nmemb); result = size * nmemb; // There can be 3 different cases, each should be handled differently: // Case 1: Check for last header line: CRLF, // http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html if (s.size() == 2u && s[0] == '\r' && s[1] == '\n') return result; // Case 2: If it is the first header, the it must be a status Line. // For all other cases, statusLine must be populated with some non-zero length string if (pHeaders->getStatusLine().length() == 0u) { pHeaders->setStatusLine(HttpHelperUtils::stripWhitespaces(s)); return result; } // Case 3: This is a usual message header, of form // message-header = field-name ":" [ field-value ] // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 pHeaders->appendHeaderString(s); } return result; }
Response* FakeConnection::search(const SearchDescription& desc) { TIMED_FUNC(FakeConnection_search); LOG(DEBUG) << " Entering FakeConnection::search"; Response* response = new Response; response->setResponseCode(ResponseCode::OK); HttpHeaders headers; headers.setHeader("Content-type","application/json"); response->setResponseHeaders(headers); std::ostringstream cos; cos << "{\"response\": {" << "\"start\": 1, \"page-length\": "; // return 10 or documents.length, whichever is smaller if (mImpl->documents.size() < 10) { cos << mImpl->documents.size(); } else { cos << 10; } cos << ", \"results\": ["; // loop over documents in map std::map<std::string,IDocumentContent*>::iterator it; int count = 0; for (it = mImpl->documents.begin();it != mImpl->documents.end() && count < 10;++it) { ++count; // iterate first as MarkLogic responses are 1 indexed, not 0 indexed if (count > 1) { cos << ","; } cos << "{\"index\": " << count << " , \"uri\": \"" << (it->first) << "\", \"score\": \"43648\" \"confidence\":\"0.418356\" \"fitness\":\"0.50947\"}"; } cos << "] } }"; //std::unique_ptr<std::string> cPtr(new std::string(cos.str())); //response->setContent(std::move(cPtr)); response->setContent(new std::string(cos.str())); response->setResponseType(ResponseType::JSON); return response; }
void HTTPSBridge::buildRequestFromHeaders(HttpHeaders &headers, std::string &request) { std::ostringstream requestStream; requestStream << headers.getMethod() << " " << headers.getRequest() << " " << "HTTP/1.0\r\n"; std::map<std::string,std::string>::iterator iter; std::map<std::string,std::string>& headersMap = headers.getHeaders(); for( iter = headersMap.begin(); iter != headersMap.end(); ++iter ) { std::string key = iter->first; std::string value = iter->second; Util::trimString(key); Util::trimString(value); if (key != "Accept-Encoding" && key != "Connection" && key != "Keep-Alive") requestStream << key << ": " << value << "\r\n"; } requestStream << "Connection: Close" << "\r\n\r\n"; if (headers.isPost()) requestStream << headers.getPostData(); request = requestStream.str(); }
void start(const QVariant &vrequest, Mode mode) { outSeq = 0; ZurlRequestPacket request; if(!request.fromVariant(vrequest)) { log_warning("failed to parse zurl request"); QVariantHash vhash = vrequest.toHash(); rid = vhash.value("id").toByteArray(); assert(!rid.isEmpty()); // app layer ensures this receiver = vhash.value("sender").toByteArray(); bool cancel = vhash.value("cancel").toBool(); if(!receiver.isEmpty() && !cancel) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); } else { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } return; } rid = request.id; receiver = request.sender; outCredits = 0; userData = request.userData; quiet = false; sentHeader = false; stuffToRead = false; bytesReceived = 0; ignorePolicies = request.ignorePolicies; // streaming only allowed on streaming interface if(mode == Worker::Stream) outStream = request.stream; else outStream = false; // some required fields if(request.method.isEmpty() || request.uri.isEmpty()) { log_warning("missing request method or missing uri"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } log_info("IN id=%s, %s %s", request.id.data(), qPrintable(request.method), request.uri.toEncoded().data()); // inbound streaming must start with sequence number of 0 if(mode == Worker::Stream && request.more && request.seq != 0) { log_warning("streamed input must start with seq 0"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } // fire and forget if(mode == Worker::Stream && receiver.isEmpty()) quiet = true; // can't use these two together if(mode == Worker::Single && request.more) { log_warning("cannot use streamed input on router interface"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } bodySent = false; inSeq = request.seq; if(!isAllowed(request.uri.host()) || (!request.connectHost.isEmpty() && !isAllowed(request.connectHost))) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "policy-violation")); return; } hreq = new HttpRequest(dns, this); connect(hreq, SIGNAL(nextAddress(const QHostAddress &)), SLOT(req_nextAddress(const QHostAddress &))); connect(hreq, SIGNAL(readyRead()), SLOT(req_readyRead())); connect(hreq, SIGNAL(bytesWritten(int)), SLOT(req_bytesWritten(int))); connect(hreq, SIGNAL(error()), SLOT(req_error())); maxResponseSize = request.maxSize; if(!request.connectHost.isEmpty()) hreq->setConnectHost(request.connectHost); hreq->setIgnoreTlsErrors(request.ignoreTlsErrors); if(request.credits != -1) outCredits += request.credits; HttpHeaders headers = request.headers; // ensure content-length (or overwrite it, if not streaming input) if((request.method == "POST" || request.method == "PUT") && (!headers.contains("content-length") || !request.more)) headers += HttpHeader("Content-Length", QByteArray::number(request.body.size())); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SLOT(timer_timeout())); timer->setSingleShot(true); timer->start(config->sessionTimeout * 1000); hreq->start(request.method, request.uri, headers); // note: unlike follow-up requests, the initial request is assumed to have a body. // if no body field is present, we act as if it is present but empty. if(!request.body.isEmpty()) { if(request.more && !request.headers.contains("content-length")) { log_warning("streamed input requires content-length"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "length-required")); return; } hreq->writeBody(request.body); } if(!request.more) { bodySent = true; hreq->endBody(); } else { // send cts ZurlResponsePacket resp; resp.credits = config->sessionBufferSize; writeResponse(resp); } }
int CGnutellaSocket::ParseHandshake() { const char* p = m_strHandshake.c_str(); const char* pend = p+m_strHandshake.length(); if (!strncmp(p, "GNUTELLA/0.6", 12)) { p += 12; p++; long code = strtol(p, (char**)&p, 10); p++; StringA codemsg; while (p < pend) { if (p[0] == '\r' && p[1] == '\n') { break; } codemsg += *p; p++; } if (*p++ != '\r') ASSERT(0); if (*p++ != '\n') ASSERT(0); // HttpHeaders headers; m_headers.AddHeaders(p); /* while (p < pend) { std::string header; while (p < pend) { if (p[0] == '\r' && p[1] == '\n') { break; } header += *p; p++; } if (*p++ != '\r') ASSERT(0); if (*p++ != '\n') ASSERT(0); m_headers.push_back(header); } ASSERT(*p == 0); */ return code; } else { ASSERT(0); return 0; } }
// return true if jsonp applied bool tryApplyJsonp(const DomainMap::JsonpConfig &config, bool *ok, QString *errorMessage) { *ok = true; // must be a GET if(requestData.method != "GET") return false; QString callbackParam = QString::fromUtf8(config.callbackParam); if(callbackParam.isEmpty()) callbackParam = "callback"; QString bodyParam; if(!config.bodyParam.isEmpty()) bodyParam = QString::fromUtf8(config.bodyParam); QUrl uri = requestData.uri; QUrlQuery query(uri); // two ways to activate JSON-P: // 1) callback param present // 2) default callback specified in configuration and body param present if(!query.hasQueryItem(callbackParam) && (config.defaultCallback.isEmpty() || bodyParam.isEmpty() || !query.hasQueryItem(bodyParam))) { return false; } QByteArray callback; if(query.hasQueryItem(callbackParam)) { callback = parsePercentEncoding(query.queryItemValue(callbackParam, QUrl::FullyEncoded).toUtf8()); if(callback.isEmpty()) { log_debug("requestsession: id=%s invalid callback parameter, rejecting", rid.second.data()); *ok = false; *errorMessage = "Invalid callback parameter."; return false; } query.removeAllQueryItems(callbackParam); } else callback = config.defaultCallback; QString method; if(query.hasQueryItem("_method")) { method = QString::fromLatin1(parsePercentEncoding(query.queryItemValue("_method", QUrl::FullyEncoded).toUtf8())); if(!validMethod(method)) { log_debug("requestsession: id=%s invalid _method parameter, rejecting", rid.second.data()); *ok = false; *errorMessage = "Invalid _method parameter."; return false; } query.removeAllQueryItems("_method"); } HttpHeaders headers; if(query.hasQueryItem("_headers")) { QJsonParseError e; QJsonDocument doc = QJsonDocument::fromJson(parsePercentEncoding(query.queryItemValue("_headers", QUrl::FullyEncoded).toUtf8()), &e); if(e.error != QJsonParseError::NoError || !doc.isObject()) { log_debug("requestsession: id=%s invalid _headers parameter, rejecting", rid.second.data()); *ok = false; *errorMessage = "Invalid _headers parameter."; return false; } QVariantMap headersMap = doc.object().toVariantMap(); QMapIterator<QString, QVariant> vit(headersMap); while(vit.hasNext()) { vit.next(); if(vit.value().type() != QVariant::String) { log_debug("requestsession: id=%s invalid _headers parameter, rejecting", rid.second.data()); *ok = false; *errorMessage = "Invalid _headers parameter."; return false; } QByteArray key = vit.key().toUtf8(); // ignore some headers that we explicitly set later on if(qstricmp(key.data(), "host") == 0) continue; if(qstricmp(key.data(), "accept") == 0) continue; headers += HttpHeader(key, vit.value().toString().toUtf8()); } query.removeAllQueryItems("_headers"); } QByteArray body; if(!bodyParam.isEmpty()) { if(query.hasQueryItem(bodyParam)) { body = parsePercentEncoding(query.queryItemValue(bodyParam, QUrl::FullyEncoded).toUtf8()); if(body.isNull()) { log_debug("requestsession: id=%s invalid body parameter, rejecting", rid.second.data()); *ok = false; *errorMessage = "Invalid body parameter."; return false; } headers.removeAll("Content-Type"); headers += HttpHeader("Content-Type", "application/json"); query.removeAllQueryItems(bodyParam); } } else { if(query.hasQueryItem("_body")) { body = parsePercentEncoding(query.queryItemValue("_body").toUtf8()); if(body.isNull()) { log_debug("requestsession: id=%s invalid _body parameter, rejecting", rid.second.data()); *ok = false; *errorMessage = "Invalid _body parameter."; return false; } query.removeAllQueryItems("_body"); } } uri.setQuery(query); // if we have no query items anymore, strip the '?' if(query.isEmpty()) { QByteArray tmp = uri.toEncoded(); if(tmp.length() > 0 && tmp[tmp.length() - 1] == '?') { tmp.truncate(tmp.length() - 1); uri = QUrl::fromEncoded(tmp, QUrl::StrictMode); } } if(method.isEmpty()) method = config.defaultMethod; requestData.method = method; requestData.uri = uri; headers += HttpHeader("Host", uri.host().toUtf8()); headers += HttpHeader("Accept", "*/*"); // carry over the rest of the headers foreach(const HttpHeader &h, requestData.headers) { if(qstricmp(h.first.data(), "host") == 0) continue; if(qstricmp(h.first.data(), "accept") == 0) continue; headers += h; } requestData.headers = headers; in += body; jsonpCallback = callback; jsonpExtendedResponse = (config.mode == DomainMap::JsonpConfig::Extended); return true; }
void start(const QVariant &vrequest, Mode mode) { outSeq = 0; outCredits = 0; quiet = false; ZhttpRequestPacket request; if(!request.fromVariant(vrequest)) { log_warning("failed to parse zurl request"); QVariantHash vhash = vrequest.toHash(); rid = vhash.value("id").toByteArray(); toAddress = vhash.value("from").toByteArray(); QByteArray type = vhash.value("type").toByteArray(); if(!toAddress.isEmpty() && type != "error" && type != "cancel") { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); } else { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } return; } rid = request.id; toAddress = request.from; userData = request.userData; sentHeader = false; stuffToRead = false; bytesReceived = 0; ignorePolicies = request.ignorePolicies; if(request.uri.isEmpty()) { log_warning("missing request uri"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } QString scheme = request.uri.scheme(); if(scheme == "https" || scheme == "http") { transport = HttpTransport; } else if(scheme == "wss" || scheme == "ws") { transport = WebSocketTransport; } else { log_warning("unsupported scheme"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } if(transport == WebSocketTransport && mode != Worker::Stream) { log_warning("websocket must be used from stream interface"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } int defaultPort; if(scheme == "https" || scheme == "wss") defaultPort = 443; else // http || wss defaultPort = 80; HttpHeaders headers = request.headers; if(transport == HttpTransport) { // fire and forget if(mode == Worker::Stream && (rid.isEmpty() || toAddress.isEmpty())) quiet = true; // streaming only allowed on streaming interface if(mode == Worker::Stream) outStream = request.stream; else outStream = false; if(request.method.isEmpty()) { log_warning("missing request method"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } log_info("IN id=%s, %s %s", request.id.data(), qPrintable(request.method), request.uri.toEncoded().data()); // inbound streaming must start with sequence number of 0 if(mode == Worker::Stream && request.more && request.seq != 0) { log_warning("streamed input must start with seq 0"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } // can't use these two together if(mode == Worker::Single && request.more) { log_warning("cannot use streamed input on router interface"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } bodySent = false; inSeq = request.seq; if(!isAllowed(request.uri.host()) || (!request.connectHost.isEmpty() && !isAllowed(request.connectHost))) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "policy-violation")); return; } QByteArray hostHeader = request.uri.host().toUtf8(); // only tack on the port if it isn't being overridden int port = request.uri.port(defaultPort); if(request.connectPort == -1 && port != defaultPort) hostHeader += ":" + QByteArray::number(port); headers.removeAll("Host"); headers += HttpHeader("Host", hostHeader); hreq = new HttpRequest(dns, this); connect(hreq, SIGNAL(nextAddress(const QHostAddress &)), SLOT(req_nextAddress(const QHostAddress &))); connect(hreq, SIGNAL(readyRead()), SLOT(req_readyRead())); connect(hreq, SIGNAL(bytesWritten(int)), SLOT(req_bytesWritten(int))); connect(hreq, SIGNAL(error()), SLOT(req_error())); maxResponseSize = request.maxSize; sessionTimeout = request.timeout; if(!request.connectHost.isEmpty()) hreq->setConnectHost(request.connectHost); if(request.connectPort != -1) request.uri.setPort(request.connectPort); hreq->setIgnoreTlsErrors(request.ignoreTlsErrors); if(request.followRedirects) hreq->setFollowRedirects(8); if(request.credits != -1) outCredits += request.credits; } else // WebSocketTransport { log_info("IN id=%s, %s", request.id.data(), request.uri.toEncoded().data()); // inbound streaming must start with sequence number of 0 if(request.seq != 0) { log_warning("websocket input must start with seq 0"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } if(toAddress.isEmpty()) { log_warning("websocket input must provide from address"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } inSeq = request.seq; if(!isAllowed(request.uri.host()) || (!request.connectHost.isEmpty() && !isAllowed(request.connectHost))) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "policy-violation")); return; } QByteArray hostHeader = request.uri.host().toUtf8(); // only tack on the port if it isn't being overridden int port = request.uri.port(defaultPort); if(request.connectPort == -1 && port != defaultPort) hostHeader += ":" + QByteArray::number(port); headers.removeAll("Host"); headers += HttpHeader("Host", hostHeader); ws = new WebSocket(dns, this); connect(ws, SIGNAL(nextAddress(const QHostAddress &)), SLOT(req_nextAddress(const QHostAddress &))); connect(ws, SIGNAL(connected()), SLOT(ws_connected())); connect(ws, SIGNAL(readyRead()), SLOT(ws_readyRead())); connect(ws, SIGNAL(framesWritten(int)), SLOT(ws_framesWritten(int))); connect(ws, SIGNAL(peerClosing()), SLOT(ws_peerClosing())); connect(ws, SIGNAL(closed()), SLOT(ws_closed())); connect(ws, SIGNAL(error()), SLOT(ws_error())); if(!request.connectHost.isEmpty()) ws->setConnectHost(request.connectHost); if(request.connectPort != -1) request.uri.setPort(request.connectPort); ws->setIgnoreTlsErrors(request.ignoreTlsErrors); ws->setMaxFrameSize(config->sessionBufferSize); if(request.credits != -1) outCredits += request.credits; } httpActivityTimer = new QTimer(this); connect(httpActivityTimer, SIGNAL(timeout()), SLOT(httpActivity_timeout())); httpActivityTimer->setSingleShot(true); httpActivityTimer->start(config->activityTimeout * 1000); if(sessionTimeout != -1) { httpSessionTimer = new QTimer(this); connect(httpSessionTimer, SIGNAL(timeout()), SLOT(httpSession_timeout())); httpSessionTimer->setSingleShot(true); httpSessionTimer->start(sessionTimeout); } if(transport == WebSocketTransport || (transport == HttpTransport && mode == Worker::Stream)) { expireTimer = new QTimer(this); connect(expireTimer, SIGNAL(timeout()), SLOT(expire_timeout())); expireTimer->setSingleShot(true); expireTimer->start(SESSION_EXPIRE); keepAliveTimer = new QTimer(this); connect(keepAliveTimer, SIGNAL(timeout()), SLOT(keepAlive_timeout())); keepAliveTimer->start(SESSION_EXPIRE / 2); } if(transport == HttpTransport) { if(!request.body.isEmpty() && !request.more && !headers.contains("Content-Length")) headers += HttpHeader("Content-Length", QByteArray::number(request.body.size())); bool hasOrMightHaveBody = (!request.body.isEmpty() || request.more); hreq->start(request.method, request.uri, headers, hasOrMightHaveBody); if(hasOrMightHaveBody) { if(!request.body.isEmpty()) hreq->writeBody(request.body); if(!request.more) { bodySent = true; hreq->endBody(); } } else bodySent = true; if(mode == Stream) { if(request.more) { // send cts ZhttpResponsePacket resp; resp.type = ZhttpResponsePacket::Credit; resp.credits = config->sessionBufferSize; writeResponse(resp); } else { // send ack ZhttpResponsePacket resp; resp.type = ZhttpResponsePacket::KeepAlive; writeResponse(resp); } } } else // WebSocketTransport { ws->start(request.uri, headers); } }