bool HttpConnection::onMessageBegin(const BufferRef& method, const BufferRef& uri, int versionMajor, int versionMinor) { TRACE("onMessageBegin: '%s', '%s', HTTP/%d.%d", method.str().c_str(), uri.str().c_str(), versionMajor, versionMinor); request_->method = method; request_->uri = uri; url_decode(input_, request_->uri); std::size_t n = request_->uri.find("?"); if (n != std::string::npos) { request_->path = request_->uri.ref(0, n); request_->query = request_->uri.ref(n + 1); } else { request_->path = request_->uri; } request_->httpVersionMajor = versionMajor; request_->httpVersionMinor = versionMinor; if (request_->supportsProtocol(1, 1)) // FIXME? HTTP/1.1 is keeping alive by default. pass "Connection: close" to close explicitely setShouldKeepAlive(true); else setShouldKeepAlive(false); // limit request uri length if (request_->uri.size() > worker().server().maxRequestUriSize()) { request_->status = HttpError::RequestUriTooLong; request_->finish(); return false; } return true; }
bool HttpConnection::onMessageBegin(const BufferRef& method, const BufferRef& uri, int versionMajor, int versionMinor) { TRACE(1, "onMessageBegin: '%s', '%s', HTTP/%d.%d", method.str().c_str(), uri.str().c_str(), versionMajor, versionMinor); request_->method = method; if (!request_->setUri(uri)) { abort(HttpStatus::BadRequest); return false; } request_->httpVersionMajor = versionMajor; request_->httpVersionMinor = versionMinor; if (request_->supportsProtocol(1, 1)) // FIXME? HTTP/1.1 is keeping alive by default. pass "Connection: close" to close explicitely setShouldKeepAlive(true); else setShouldKeepAlive(false); // limit request uri length if (request_->unparsedUri.size() > worker().server().maxRequestUriSize()) { request_->status = HttpStatus::RequestUriTooLong; request_->finish(); return false; } return true; }
/** * Callback, invoked on each successfully parsed response header key/value pair. */ bool HealthMonitor::onMessageHeader(const BufferRef& name, const BufferRef& value) { TRACE("onResponseHeader(name:%s, value:%s)", name.str().c_str(), value.str().c_str()); if (x0::iequals(name, "Status")) { int status = value.ref(0, value.find(' ')).toInt(); responseCode_ = static_cast<x0::HttpStatus>(status); } return true; }
bool HttpFileMgr::Settings::openMimeTypes(const std::string& path) { Buffer input; if (!readFile(path, &input)) return false; auto lines = Tokenizer<BufferRef, Buffer>::tokenize(input, "\n"); mimetypes.clear(); for (auto line: lines) { line = line.trim(); auto columns = Tokenizer<BufferRef, BufferRef>::tokenize(line, " \t"); auto ci = columns.begin(), ce = columns.end(); BufferRef mime = ci != ce ? *ci++ : BufferRef(); if (!mime.empty() && mime[0] != '#') { for (; ci != ce; ++ci) { mimetypes[ci->str()] = mime.str(); } } } return true; }
/** * Callback, invoked on successfully parsed response status line. */ bool HealthMonitor::onMessageBegin(int versionMajor, int versionMinor, int code, const BufferRef& text) { TRACE("onMessageBegin: (HTTP/%d.%d, %d, '%s')", versionMajor, versionMinor, code, text.str().c_str()); responseCode_ = static_cast<HttpStatus>(code); return true; }
bool HttpConnection::onMessageHeader(const BufferRef& name, const BufferRef& value) { if (request_->isFinished()) { // this can happen when the request has failed some checks and thus, // a client error message has been sent already. // we need to "parse" the remaining content anyways. TRACE("onMessageHeader() skip \"%s\": \"%s\"", name.str().c_str(), value.str().c_str()); return true; } TRACE("onMessageHeader() \"%s\": \"%s\"", name.str().c_str(), value.str().c_str()); if (iequals(name, "Host")) { auto i = value.find(':'); if (i != BufferRef::npos) request_->hostname = value.ref(0, i); else request_->hostname = value; TRACE(" -- hostname set to \"%s\"", request_->hostname.str().c_str()); } else if (iequals(name, "Connection")) { if (iequals(value, "close")) setShouldKeepAlive(false); else if (iequals(value, "keep-alive")) setShouldKeepAlive(true); } // limit the size of a single request header if (name.size() + value.size() > worker().server().maxRequestHeaderSize()) { TRACE("header too long. got %ld / %ld", name.size() + value.size(), worker().server().maxRequestHeaderSize()); request_->status = HttpError::RequestEntityTooLarge; request_->finish(); return false; } // limit the number of request headers if (request_->requestHeaders.size() > worker().server().maxRequestHeaderCount()) { TRACE("header count exceeded. got %ld / %ld", request_->requestHeaders.size(), worker().server().maxRequestHeaderCount()); request_->status = HttpError::RequestEntityTooLarge; request_->finish(); return false; } request_->requestHeaders.push_back(HttpRequestHeader(name, value)); return true; }
void print(const BufferRef& v, const char *msg = 0) { char prefix[64]; if (msg && *msg) snprintf(prefix, sizeof(prefix), "\nbuffer.view(%s)", msg); else snprintf(prefix, sizeof(prefix), "\nbuffer.view"); if (v) printf("\n%s: '%s' (size=%zu)\n", prefix, v.str().c_str(), v.size()); else printf("\n%s: NULL\n", prefix); }
/** callback, invoked on every successfully parsed response header. * * We will pass this header directly to the client's response, * if that is NOT a connection-level header. */ bool HttpProxy::ProxyConnection::onMessageHeader(const BufferRef& name, const BufferRef& value) { TRACE("ProxyConnection(%p).onHeader('%s', '%s')", (void*)this, name.str().c_str(), value.str().c_str()); // XXX do not allow origin's connection-level response headers to be passed to the client. if (iequals(name, "Connection")) goto skip; if (iequals(name, "Transfer-Encoding")) goto skip; if (cloak_ && iequals(name, "Server")) { TRACE("skipping \"Server\"-header"); goto skip; } request_->responseHeaders.push_back(name.str(), value.str()); return true; skip: TRACE("skip (connection-)level header"); return true; }
void FileInfoService::Config::loadMimetypes(const std::string& filename) { Buffer input(x0::read_file(filename)); auto lines = Tokenizer<BufferRef, Buffer>::tokenize(input, "\n"); mimetypes.clear(); for (auto line: lines) { line = line.trim(); auto columns = Tokenizer<BufferRef, BufferRef>::tokenize(line, " \t"); auto ci = columns.begin(), ce = columns.end(); BufferRef mime = ci != ce ? *ci++ : BufferRef(); if (!mime.empty() && mime[0] != '#') { for (; ci != ce; ++ci) { mimetypes[ci->str()] = mime.str(); } } } }
/** callback, invoked when the origin server has passed us the response status line. * * We will use the status code only. * However, we could pass the text field, too - once x0 core supports it. */ bool HttpProxy::ProxyConnection::onMessageBegin(int major, int minor, int code, const BufferRef& text) { TRACE("ProxyConnection(%p).status(HTTP/%d.%d, %d, '%s')", (void*)this, major, minor, code, text.str().c_str()); request_->status = static_cast<HttpError>(code); TRACE("status: %d", (int)request_->status); return true; }