void PhpResultGenerator::generateAtom (StringBuffer& output, string const& value) const { output.appendText("s:"); output.appendInteger(value.size()); output.appendText(":\""); output.appendText(value); output.appendText("\";"); }
void XmlResultGenerator::generateAtom (StringBuffer& output, char const* value) const { if (value == 0) { output.appendText(""); } else { output.appendText(StringUtils::escapeXml(value)); } }
void JsonResultGenerator::generateAtom (StringBuffer& output, bool value) const { if (value) { output.appendText("true", 4); } else { output.appendText("false", 5); } }
void XmlResultGenerator::generateAtom (StringBuffer& output, char const* value, size_t length, bool) const { if (value == 0) { output.appendText(""); } else { string v(value, length); output.appendText(StringUtils::escapeXml(v)); } }
void JsonResultGenerator::generateAtom (StringBuffer& output, char const* value) const { if (value == 0) { output.appendText("null"); } else { output.appendText("\""); output.appendText(StringUtils::escapeUnicode(value)); output.appendText("\""); } }
void PhpResultGenerator::generateAtom (StringBuffer& output, char const* value) const { if (value == 0) { output.appendText("N;"); } else { output.appendText("s:"); output.appendInteger(strlen(value)); output.appendText(":\""); output.appendText(value); output.appendText("\";"); } }
void PhpResultGenerator::generateAtom (StringBuffer& output, char const* value, size_t length, bool) const { if (value == 0) { output.appendText("N;"); } else { output.appendText("s:"); output.appendInteger(length); output.appendText(":\""); output.appendText(value, length); output.appendText("\";"); } }
void XmlResultGenerator::generateAtom (StringBuffer& output, float value) const { if (value == 0.0) { output.appendText("0.0", 3); return; } int intType = _fpclass(value); switch (intType) { case _FPCLASS_PN: case _FPCLASS_NN: case _FPCLASS_NZ: case _FPCLASS_PZ: { output.appendDecimal(value); break; } case _FPCLASS_NINF: { generateAtom(output, "-INF"); break; } case _FPCLASS_PINF: { generateAtom(output, "INF"); break; } default: { generateAtom(output, "NAN"); break; } } }
void JsonResultGenerator::generateAtom (StringBuffer& output, char const* value, size_t length, bool quote) const { if (value == 0) { if (quote) { output.appendText("null"); } } else { string v(value, length); if (quote) { output.appendText("\""); output.appendText(StringUtils::escapeUnicode(v)); output.appendText("\""); } else { output.appendText(v); } } }
ResultStatus CubeWorker::setCellValue(const string& areaIdentifier, const string& sessionIdentifier, const IdentifiersType& path, double value, SplashMode splashMode, bool addValue) { StringBuffer sb; sb.appendText("DOUBLE;"); sb.appendInteger(dbid); sb.appendChar(';'); sb.appendInteger(cubeid); sb.appendChar(';'); sb.appendText(StringUtils::escapeString(areaIdentifier)); sb.appendChar(';'); sb.appendText(StringUtils::escapeString(sessionIdentifier)); sb.appendChar(';'); sb.appendText(buildPathString(&path)); sb.appendChar(';'); sb.appendDecimal(value); sb.appendChar(';'); sb.appendInteger(PaloJob::splashNumber(splashMode)); sb.appendChar(';'); sb.appendInteger((int)addValue); // we need to change the job-type // dispatcher->downgradeCurrentJobs(); // send set-cell-value request to worker vector<string> result; ResultStatus status = execute(sb.c_str(), result); if (status != RESULT_OK) { return status; } if (isErrorStatus(result)) { throw WorkerException(result[0].substr(6), true); } else if (isExceptionStatus(result)) { throw WorkerException(result[0].substr(10), true); } numFailures = 0; return RESULT_OK; }
void PhpResultGenerator::generateAtom (StringBuffer& output, float value) const { output.appendText("d:"); if (value == 0.0) { output.appendText("0.0", 3); } else if (isnormal(value)) { output.appendDecimal(value); } else { int a = isinf(value); if (a == -1) { output.appendText("-INF"); } else if (a == 1) { output.appendText("INF"); } else /* if (isnan(value)) */ { output.appendText("NAN"); } } output.appendText(";"); }
void HttpCommTask::finishedChunked () { StringBuffer* buffer = new StringBuffer(TRI_UNKNOWN_MEM_ZONE, 6); buffer->appendText("0\r\n\r\n"); _writeBuffers.push_back(buffer); #ifdef TRI_ENABLE_FIGURES _writeBuffersStats.push_back(0); #endif _isChunked = false; _requestPending = false; fillWriteBuffer(); processRead(); }
void HttpServerTask::addResponse(HttpResponse* response) { StringBuffer * buffer; // save header buffer = new StringBuffer(); buffer->replaceText(response->getHeader()); buffer->appendText(response->getBody()); writeBuffers.push_back(buffer); // clear body response->getBody().clear(); // start output fillWriteBuffer(); }
void XmlResultGenerator::generateAtom (StringBuffer& output, double value) const { if (value == 0.0) { output.appendText("0.0", 3); } else if (isnormal(value)) { output.appendDecimal(value); } else { int a = isinf(value); if (a == -1) { generateAtom(output, "-INF"); } else if (a == 1) { generateAtom(output, "INF"); } else /* if (isnan(value)) */ { generateAtom(output, "NAN"); } } }
void slurp (string const& filename, StringBuffer& result) { int fd = TRI_OPEN(filename.c_str(), O_RDONLY); if (fd == -1) { THROW_FILE_OPEN_ERROR("open", filename, "O_RDONLY", errno); } // reserve space in the output buffer off_t fileSize = size(filename); if (fileSize > 0) { result.reserve((size_t) fileSize); } char buffer[10240]; while (true) { ssize_t n = TRI_READ(fd, buffer, sizeof(buffer)); if (n == 0) { break; } if (n < 0) { TRI_CLOSE(fd); LOG_TRACE("read failed for '%s' with %s and result %d on fd %d", filename.c_str(), strerror(errno), (int) n, fd); THROW_FILE_FUNC_ERROR("read", "", errno); } result.appendText(buffer, n); } TRI_CLOSE(fd); }
void VariantInt64::print (StringBuffer& buffer, size_t) const { buffer.appendText("(int64) "); buffer.appendInteger(getValue()); buffer.appendEol(); }
void VariantString::print (StringBuffer& buffer, size_t) const { buffer.appendText(_value.c_str(), _value.length()); buffer.appendEol(); }
void PhpResultGenerator::generateAtom (StringBuffer& output, uint64_t value) const { output.appendText("i:"); output.appendInteger(value); output.appendText(";"); }
void PhpResultGenerator::generateAtom (StringBuffer& output, bool value) const { output.appendText(value ? "b:1;" : "b:0;"); }
void XmlResultGenerator::generateResultEnd (StringBuffer& output, VariantObject*) const { output.appendText("</result>"); }
void VariantDate::print (StringBuffer& buffer, size_t) const { buffer.appendText("(date) "); buffer.appendDecimal(getValue()); buffer.appendEol(); }
void XmlResultGenerator::generateAtom (StringBuffer& output, bool value) const { output.appendText(value ? "true" : "false"); }
void JsonResultGenerator::generateAtom (StringBuffer& output, string const& value) const { output.appendText("\""); output.appendText(StringUtils::escapeUnicode(value)); output.appendText("\""); }
void XmlResultGenerator::generateAtom (StringBuffer& output, string const& value) const { output.appendText(StringUtils::escapeXml(value)); }
bool HttpCommTask::processRead () { if (_requestPending || _readBuffer->c_str() == nullptr) { return false; } bool handleRequest = false; // still trying to read the header fields if (! _readRequestBody) { // starting a new request if (_newRequest) { #ifdef TRI_ENABLE_FIGURES RequestStatisticsAgent::acquire(); RequestStatisticsAgentSetReadStart(this); #endif _newRequest = false; _startPosition = _readPosition; _httpVersion = HttpRequest::HTTP_UNKNOWN; _requestType = HttpRequest::HTTP_REQUEST_ILLEGAL; _fullUrl = ""; _denyCredentials = false; _acceptDeflate = false; _sinceCompactification++; } const char * ptr = _readBuffer->c_str() + _readPosition; const char * end = _readBuffer->end() - 3; for (; ptr < end; ptr++) { if (ptr[0] == '\r' && ptr[1] == '\n' && ptr[2] == '\r' && ptr[3] == '\n') { break; } } // check if header is too large size_t headerLength = ptr - (_readBuffer->c_str() + _startPosition); if (headerLength > _maximalHeaderSize) { LOG_WARNING("maximal header size is %d, request header size is %d", (int) _maximalHeaderSize, (int) headerLength); // header is too large HttpResponse response(HttpResponse::REQUEST_HEADER_FIELDS_TOO_LARGE, getCompatibility()); // we need to close the connection, because there is no way we // know what to remove and then continue resetState(true); handleResponse(&response); return false; } // header is complete if (ptr < end) { _readPosition = ptr - _readBuffer->c_str() + 4; LOG_TRACE("HTTP READ FOR %p: %s", (void*) this, string(_readBuffer->c_str() + _startPosition, _readPosition - _startPosition).c_str()); // check that we know, how to serve this request // and update the connection information, i. e. client and server addresses and ports // and create a request context for that request _request = _server->handlerFactory()->createRequest( _connectionInfo, _readBuffer->c_str() + _startPosition, _readPosition - _startPosition); if (_request == nullptr) { LOG_ERROR("cannot generate request"); // internal server error HttpResponse response(HttpResponse::SERVER_ERROR, getCompatibility()); // we need to close the connection, because there is no way we // know how to remove the body and then continue resetState(true); handleResponse(&response); return false; } _request->setClientTaskId(_taskId); // check HTTP protocol version _httpVersion = _request->httpVersion(); if (_httpVersion != HttpRequest::HTTP_1_0 && _httpVersion != HttpRequest::HTTP_1_1) { HttpResponse response(HttpResponse::HTTP_VERSION_NOT_SUPPORTED, getCompatibility()); // we need to close the connection, because there is no way we // know what to remove and then continue resetState(true); handleResponse(&response); return false; } // check max URL length _fullUrl = _request->fullUrl(); if (_fullUrl.size() > 16384) { HttpResponse response(HttpResponse::REQUEST_URI_TOO_LONG, getCompatibility()); // we need to close the connection, because there is no way we // know what to remove and then continue resetState(true); handleResponse(&response); return false; } // update the connection information, i. e. client and server addresses and ports _request->setProtocol(_server->protocol()); LOG_TRACE("server port %d, client port %d", (int) _connectionInfo.serverPort, (int) _connectionInfo.clientPort); // set body start to current position _bodyPosition = _readPosition; _bodyLength = 0; // keep track of the original value of the "origin" request header (if any) // we need this value to handle CORS requests _origin = _request->header("origin"); if (! _origin.empty()) { // check for Access-Control-Allow-Credentials header bool found; string const& allowCredentials = _request->header("access-control-allow-credentials", found); if (found) { _denyCredentials = ! StringUtils::boolean(allowCredentials); } } // store the original request's type. we need it later when responding // (original request object gets deleted before responding) _requestType = _request->requestType(); #ifdef TRI_ENABLE_FIGURES RequestStatisticsAgentSetRequestType(this, _requestType); #endif // handle different HTTP methods switch (_requestType) { case HttpRequest::HTTP_REQUEST_GET: case HttpRequest::HTTP_REQUEST_DELETE: case HttpRequest::HTTP_REQUEST_HEAD: case HttpRequest::HTTP_REQUEST_OPTIONS: case HttpRequest::HTTP_REQUEST_POST: case HttpRequest::HTTP_REQUEST_PUT: case HttpRequest::HTTP_REQUEST_PATCH: { // technically, sending a body for an HTTP DELETE request is not forbidden, but it is not explicitly supported const bool expectContentLength = (_requestType == HttpRequest::HTTP_REQUEST_POST || _requestType == HttpRequest::HTTP_REQUEST_PUT || _requestType == HttpRequest::HTTP_REQUEST_PATCH || _requestType == HttpRequest::HTTP_REQUEST_OPTIONS || _requestType == HttpRequest::HTTP_REQUEST_DELETE); if (! checkContentLength(expectContentLength)) { return false; } if (_bodyLength == 0) { handleRequest = true; } break; } default: { size_t l = _readPosition - _startPosition; if (6 < l) { l = 6; } LOG_WARNING("got corrupted HTTP request '%s'", string(_readBuffer->c_str() + _startPosition, l).c_str()); // bad request, method not allowed HttpResponse response(HttpResponse::METHOD_NOT_ALLOWED, getCompatibility()); // we need to close the connection, because there is no way we // know what to remove and then continue resetState(true); // force a socket close, response will be ignored! TRI_CLOSE_SOCKET(_commSocket); TRI_invalidatesocket(&_commSocket); // might delete this handleResponse(&response); return false; } } // ............................................................................. // check if server is active // ............................................................................. Scheduler const* scheduler = _server->scheduler(); if (scheduler != nullptr && ! scheduler->isActive()) { // server is inactive and will intentionally respond with HTTP 503 LOG_TRACE("cannot serve request - server is inactive"); HttpResponse response(HttpResponse::SERVICE_UNAVAILABLE, getCompatibility()); // we need to close the connection, because there is no way we // know what to remove and then continue resetState(true); handleResponse(&response); return false; } // check for a 100-continue if (_readRequestBody) { bool found; string const& expect = _request->header("expect", found); if (found && StringUtils::trim(expect) == "100-continue") { LOG_TRACE("received a 100-continue request"); StringBuffer* buffer = new StringBuffer(TRI_UNKNOWN_MEM_ZONE); buffer->appendText("HTTP/1.1 100 (Continue)\r\n\r\n"); _writeBuffers.push_back(buffer); #ifdef TRI_ENABLE_FIGURES _writeBuffersStats.push_back(0); #endif fillWriteBuffer(); } } } else { size_t l = (_readBuffer->end() - _readBuffer->c_str()); if (_startPosition + 4 <= l) { _readPosition = l - 4; } } } // readRequestBody might have changed, so cannot use else if (_readRequestBody) { if (_readBuffer->length() - _bodyPosition < _bodyLength) { setKeepAliveTimeout(60.0); // let client send more return false; } // read "bodyLength" from read buffer and add this body to "httpRequest" _request->setBody(_readBuffer->c_str() + _bodyPosition, _bodyLength); LOG_TRACE("%s", string(_readBuffer->c_str() + _bodyPosition, _bodyLength).c_str()); // remove body from read buffer and reset read position _readRequestBody = false; handleRequest = true; } // ............................................................................. // request complete // // we have to delete request in here or pass it to a handler, which will delete // it // ............................................................................. if (! handleRequest) { return false; } RequestStatisticsAgentSetReadEnd(this); RequestStatisticsAgentAddReceivedBytes(this, _bodyPosition - _startPosition + _bodyLength); bool isOptions = (_requestType == HttpRequest::HTTP_REQUEST_OPTIONS); resetState(false); // ............................................................................. // keep-alive handling // ............................................................................. string connectionType = StringUtils::tolower(_request->header("connection")); if (connectionType == "close") { // client has sent an explicit "Connection: Close" header. we should close the connection LOG_DEBUG("connection close requested by client"); _closeRequested = true; } else if (_request->isHttp10() && connectionType != "keep-alive") { // HTTP 1.0 request, and no "Connection: Keep-Alive" header sent // we should close the connection LOG_DEBUG("no keep-alive, connection close requested by client"); _closeRequested = true; } else if (_keepAliveTimeout <= 0.0) { // if keepAliveTimeout was set to 0.0, we'll close even keep-alive connections immediately LOG_DEBUG("keep-alive disabled by admin"); _closeRequested = true; } // we keep the connection open in all other cases (HTTP 1.1 or Keep-Alive header sent) // ............................................................................. // authenticate // ............................................................................. auto const compatibility = _request->compatibility(); HttpResponse::HttpResponseCode authResult = _server->handlerFactory()->authenticateRequest(_request); // authenticated or an OPTIONS request. OPTIONS requests currently go unauthenticated if (authResult == HttpResponse::OK || isOptions) { // handle HTTP OPTIONS requests directly if (isOptions) { processCorsOptions(compatibility); } else { processRequest(compatibility); } } // not found else if (authResult == HttpResponse::NOT_FOUND) { HttpResponse response(authResult, compatibility); response.setContentType("application/json; charset=utf-8"); response.body() .appendText("{\"error\":true,\"errorMessage\":\"") .appendText(TRI_errno_string(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND)) .appendText("\",\"code\":") .appendInteger((int) authResult) .appendText(",\"errorNum\":") .appendInteger(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND) .appendText("}"); clearRequest(); handleResponse(&response); } // forbidden else if (authResult == HttpResponse::FORBIDDEN) { HttpResponse response(authResult, compatibility); response.setContentType("application/json; charset=utf-8"); response.body() .appendText("{\"error\":true,\"errorMessage\":\"change password\",\"code\":") .appendInteger((int) authResult) .appendText(",\"errorNum\":") .appendInteger(TRI_ERROR_USER_CHANGE_PASSWORD) .appendText("}"); clearRequest(); handleResponse(&response); } // not authenticated else { HttpResponse response(HttpResponse::UNAUTHORIZED, compatibility); const string realm = "basic realm=\"" + _server->handlerFactory()->authenticationRealm(_request) + "\""; if (sendWwwAuthenticateHeader()) { response.setHeader("www-authenticate", strlen("www-authenticate"), realm.c_str()); } clearRequest(); handleResponse(&response); } return true; }
void VariantNull::print (StringBuffer& buffer, size_t) const { buffer.appendText("(null)"); buffer.appendEol(); }
void HttpCommTask::addResponse (HttpResponse* response) { // CORS response handling if (! _origin.empty()) { // the request contained an Origin header. We have to send back the // access-control-allow-origin header now LOG_TRACE("handling CORS response"); response->setHeader("access-control-expose-headers", strlen("access-control-expose-headers"), "etag, content-encoding, content-length, location, server, x-arango-errors, x-arango-async-id"); // TODO: check whether anyone actually needs these headers in the browser: // x-arango-replication-checkmore, x-arango-replication-lastincluded, // x-arango-replication-lasttick, x-arango-replication-active"); // send back original value of "Origin" header response->setHeader("access-control-allow-origin", strlen("access-control-allow-origin"), _origin); // send back "Access-Control-Allow-Credentials" header if (_denyCredentials) { response->setHeader("access-control-allow-credentials", "false"); } else { response->setHeader("access-control-allow-credentials", "true"); } } // CORS request handling EOF // set "connection" header if (_closeRequested) { response->setHeader("connection", strlen("connection"), "Close"); } else { // keep-alive is the default response->setHeader("connection", strlen("connection"), "Keep-Alive"); } size_t responseBodyLength = response->bodySize(); if (_requestType == HttpRequest::HTTP_REQUEST_HEAD) { // clear body if this is an HTTP HEAD request // HEAD must not return a body response->headResponse(responseBodyLength); } // else { // // to enable automatic deflating of responses, active this. // // deflate takes a lot of CPU time so it should only be enabled for // // dedicated purposes and not generally // if (responseBodyLength > 16384 && _acceptDeflate) { // response->deflate(); // responseBodyLength = response->bodySize(); // } // } // reserve some outbuffer size StringBuffer* buffer = new StringBuffer(TRI_UNKNOWN_MEM_ZONE, responseBodyLength + 128); // write header response->writeHeader(buffer); // write body if (_requestType != HttpRequest::HTTP_REQUEST_HEAD) { if (_isChunked) { if (0 != responseBodyLength) { buffer->appendHex(response->body().length()); buffer->appendText("\r\n"); buffer->appendText(response->body()); buffer->appendText("\r\n"); } } else { buffer->appendText(response->body()); } } _writeBuffers.push_back(buffer); LOG_TRACE("HTTP WRITE FOR %p: %s", (void*) this, buffer->c_str()); // clear body response->body().clear(); double totalTime; #ifdef TRI_ENABLE_FIGURES _writeBuffersStats.push_back(RequestStatisticsAgent::transfer()); totalTime = RequestStatisticsAgent::elapsedSinceReadStart(); #else totalTime = 0.0; #endif // disable the following statement to prevent excessive logging of incoming requests LOG_USAGE(",\"http-request\",\"%s\",\"%s\",\"%s\",%d,%llu,%llu,\"%s\",%.6f", _connectionInfo.clientAddress.c_str(), HttpRequest::translateMethod(_requestType).c_str(), HttpRequest::translateVersion(_httpVersion).c_str(), (int) response->responseCode(), (unsigned long long) _originalBodyLength, (unsigned long long) responseBodyLength, _fullUrl.c_str(), totalTime); // start output fillWriteBuffer(); }
void XmlResultGenerator::generateResultBegin (StringBuffer& output, VariantObject*) const { output.appendText("<?xml version=\"1.0\"?>\n<result>"); }