//////////////////////////////////////////////////////////////////////////////// /// @brief http communication /// /// @file /// /// DISCLAIMER /// /// Copyright 2014-2015 ArangoDB GmbH, Cologne, Germany /// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Achim Brandt /// @author Copyright 2014-2015, ArangoDB GmbH, Cologne, Germany /// @author Copyright 2009-2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGODB_HTTP_SERVER_HTTP_COMM_TASK_H #define ARANGODB_HTTP_SERVER_HTTP_COMM_TASK_H 1 #include "Basics/Mutex.h" #include "Basics/StringBuffer.h" #include "Scheduler/SocketTask.h" namespace triagens { namespace rest { class HttpCommTask; class HttpHandler; class HttpRequest; class HttpResponse; class HttpServer; class HttpServerJob; // ----------------------------------------------------------------------------- // --SECTION-- class AsyncChunkedTask // ----------------------------------------------------------------------------- class AsyncChunkedTask : public Task { public: explicit AsyncChunkedTask (HttpCommTask*); ~AsyncChunkedTask (); public: int signalChunk (std::string const&); bool setup (Scheduler*, EventLoop) override; void cleanup () override; bool handleEvent (EventToken, EventType) override; bool handleAsync (); void signal (); private: HttpCommTask* _output; bool _done; basics::StringBuffer* _data; basics::Mutex _dataLock; //////////////////////////////////////////////////////////////////////////////// /// @brief event for async signals //////////////////////////////////////////////////////////////////////////////// EventToken _watcher; }; // ----------------------------------------------------------------------------- // --SECTION-- class HttpCommTask // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief http communication //////////////////////////////////////////////////////////////////////////////// class HttpCommTask : public SocketTask, public RequestStatisticsAgent { HttpCommTask (HttpCommTask const&) = delete; HttpCommTask const& operator= (HttpCommTask const&) = delete; // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- public: //////////////////////////////////////////////////////////////////////////////// /// @brief constructs a new task //////////////////////////////////////////////////////////////////////////////// HttpCommTask (HttpServer*, TRI_socket_t, const ConnectionInfo&, double keepAliveTimeout); //////////////////////////////////////////////////////////////////////////////// /// @brief destructs a task //////////////////////////////////////////////////////////////////////////////// protected: ~HttpCommTask (); // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- public: //////////////////////////////////////////////////////////////////////////////// /// @brief sets the current handler for the task //////////////////////////////////////////////////////////////////////////////// void setHandler (HttpHandler* handler) { TRI_ASSERT(_handler == nullptr); TRI_ASSERT(handler != nullptr); _handler = handler; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the current job. note: this may be a nullptr //////////////////////////////////////////////////////////////////////////////// HttpServerJob* job () const { return _job; } //////////////////////////////////////////////////////////////////////////////// /// @brief sets the current job //////////////////////////////////////////////////////////////////////////////// void setCurrentJob (HttpServerJob* job) { TRI_ASSERT(_job == nullptr); _job = job; } //////////////////////////////////////////////////////////////////////////////// /// @brief clears the current job //////////////////////////////////////////////////////////////////////////////// void clearCurrentJob () { _job = nullptr; } //////////////////////////////////////////////////////////////////////////////// /// @brief signals a new chunk //////////////////////////////////////////////////////////////////////////////// int signalChunk (const std::string&); //////////////////////////////////////////////////////////////////////////////// /// @brief handles response //////////////////////////////////////////////////////////////////////////////// void handleResponse (HttpResponse*); //////////////////////////////////////////////////////////////////////////////// /// @brief reads data from the socket //////////////////////////////////////////////////////////////////////////////// bool processRead (); //////////////////////////////////////////////////////////////////////////////// /// @brief sends more chunked data //////////////////////////////////////////////////////////////////////////////// void sendChunk (basics::StringBuffer*); //////////////////////////////////////////////////////////////////////////////// /// @brief chunking is finished //////////////////////////////////////////////////////////////////////////////// void finishedChunked (); //////////////////////////////////////////////////////////////////////////////// /// @brief task set up complete //////////////////////////////////////////////////////////////////////////////// void setupDone (); // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- private: //////////////////////////////////////////////////////////////////////////////// /// @brief reads data from the socket //////////////////////////////////////////////////////////////////////////////// void addResponse (HttpResponse*); //////////////////////////////////////////////////////////////////////////////// /// check the content-length header of a request and fail it is broken //////////////////////////////////////////////////////////////////////////////// bool checkContentLength (bool expectContentLength); //////////////////////////////////////////////////////////////////////////////// /// @brief fills the write buffer //////////////////////////////////////////////////////////////////////////////// void fillWriteBuffer (); //////////////////////////////////////////////////////////////////////////////// /// @brief handles CORS options //////////////////////////////////////////////////////////////////////////////// void processCorsOptions (uint32_t compatibility); //////////////////////////////////////////////////////////////////////////////// /// @brief processes a request //////////////////////////////////////////////////////////////////////////////// void processRequest (uint32_t compatibility); //////////////////////////////////////////////////////////////////////////////// /// @brief clears the request object //////////////////////////////////////////////////////////////////////////////// void clearRequest (); //////////////////////////////////////////////////////////////////////////////// /// @brief resets the internal state /// /// this method can be called to clean up when the request handling aborts /// prematurely //////////////////////////////////////////////////////////////////////////////// void resetState (bool close); //////////////////////////////////////////////////////////////////////////////// /// @brief decides whether or not we should send back a www-authenticate header //////////////////////////////////////////////////////////////////////////////// bool sendWwwAuthenticateHeader () const; //////////////////////////////////////////////////////////////////////////////// /// @brief get request compatibility //////////////////////////////////////////////////////////////////////////////// int32_t getCompatibility () const; // ----------------------------------------------------------------------------- // --SECTION-- Task methods // ----------------------------------------------------------------------------- protected: //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// bool setup (Scheduler* scheduler, EventLoop loop) override; //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// void cleanup () override; //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// bool handleEvent (EventToken token, EventType events) override; // ----------------------------------------------------------------------------- // --SECTION-- AsyncTask methods // ----------------------------------------------------------------------------- protected: //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// bool handleAsync (); public: //////////////////////////////////////////////////////////////////////////////// /// @brief signals the task /// /// Note that this method can only be called after the task has been registered. //////////////////////////////////////////////////////////////////////////////// void signal (); // ----------------------------------------------------------------------------- // --SECTION-- SocketTask methods // ----------------------------------------------------------------------------- protected: //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// bool handleRead () override; //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// void completedWriteBuffer () override; //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// void handleTimeout () override; // ----------------------------------------------------------------------------- // --SECTION-- protected variables // ----------------------------------------------------------------------------- protected: //////////////////////////////////////////////////////////////////////////////// /// @brief connection info //////////////////////////////////////////////////////////////////////////////// ConnectionInfo _connectionInfo; //////////////////////////////////////////////////////////////////////////////// /// @brief the underlying server //////////////////////////////////////////////////////////////////////////////// HttpServer* const _server; // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- private: //////////////////////////////////////////////////////////////////////////////// /// @brief event for async signals //////////////////////////////////////////////////////////////////////////////// EventToken _watcher; //////////////////////////////////////////////////////////////////////////////// /// @brief the current job //////////////////////////////////////////////////////////////////////////////// HttpServerJob* _job; //////////////////////////////////////////////////////////////////////////////// /// @brief the current handler //////////////////////////////////////////////////////////////////////////////// HttpHandler* _handler; //////////////////////////////////////////////////////////////////////////////// /// @brief write buffers //////////////////////////////////////////////////////////////////////////////// std::deque _writeBuffers; //////////////////////////////////////////////////////////////////////////////// /// @brief statistics buffers //////////////////////////////////////////////////////////////////////////////// std::deque _writeBuffersStats; //////////////////////////////////////////////////////////////////////////////// /// @brief current read position //////////////////////////////////////////////////////////////////////////////// size_t _readPosition; //////////////////////////////////////////////////////////////////////////////// /// @brief start of the body position //////////////////////////////////////////////////////////////////////////////// size_t _bodyPosition; //////////////////////////////////////////////////////////////////////////////// /// @brief body length //////////////////////////////////////////////////////////////////////////////// size_t _bodyLength; //////////////////////////////////////////////////////////////////////////////// /// @brief true if request is complete but not handled //////////////////////////////////////////////////////////////////////////////// bool _requestPending; //////////////////////////////////////////////////////////////////////////////// /// @brief true if a close has been requested by the client //////////////////////////////////////////////////////////////////////////////// bool _closeRequested; //////////////////////////////////////////////////////////////////////////////// /// @brief true if reading the request body //////////////////////////////////////////////////////////////////////////////// bool _readRequestBody; //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not to allow credentialed requests /// /// this is only used for CORS //////////////////////////////////////////////////////////////////////////////// bool _denyCredentials; //////////////////////////////////////////////////////////////////////////////// /// @brief whether the client accepts deflate algorithm //////////////////////////////////////////////////////////////////////////////// bool _acceptDeflate; //////////////////////////////////////////////////////////////////////////////// /// @brief new request started //////////////////////////////////////////////////////////////////////////////// bool _newRequest; //////////////////////////////////////////////////////////////////////////////// /// @brief true if within a chunked response //////////////////////////////////////////////////////////////////////////////// bool _isChunked; //////////////////////////////////////////////////////////////////////////////// /// @brief the request with possible incomplete body //////////////////////////////////////////////////////////////////////////////// HttpRequest* _request; //////////////////////////////////////////////////////////////////////////////// /// @brief http version number used //////////////////////////////////////////////////////////////////////////////// HttpRequest::HttpVersion _httpVersion; //////////////////////////////////////////////////////////////////////////////// /// @brief type of request (GET, POST, ...) //////////////////////////////////////////////////////////////////////////////// HttpRequest::HttpRequestType _requestType; //////////////////////////////////////////////////////////////////////////////// /// @brief value of requested URL //////////////////////////////////////////////////////////////////////////////// std::string _fullUrl; //////////////////////////////////////////////////////////////////////////////// /// @brief value of the HTTP origin header the client sent (if any). /// /// this is only used for CORS //////////////////////////////////////////////////////////////////////////////// std::string _origin; //////////////////////////////////////////////////////////////////////////////// /// @brief start position of current request //////////////////////////////////////////////////////////////////////////////// size_t _startPosition; //////////////////////////////////////////////////////////////////////////////// /// @brief number of requests since last compactification //////////////////////////////////////////////////////////////////////////////// size_t _sinceCompactification; //////////////////////////////////////////////////////////////////////////////// /// @brief original body length //////////////////////////////////////////////////////////////////////////////// size_t _originalBodyLength; //////////////////////////////////////////////////////////////////////////////// /// @brief asnyc task for signaling when a new chunk is available //////////////////////////////////////////////////////////////////////////////// AsyncChunkedTask _chunkedTask; //////////////////////////////////////////////////////////////////////////////// /// @brief task ready //////////////////////////////////////////////////////////////////////////////// std::atomic _setupDone; //////////////////////////////////////////////////////////////////////////////// /// @brief the maximal header size //////////////////////////////////////////////////////////////////////////////// static size_t const MaximalHeaderSize; //////////////////////////////////////////////////////////////////////////////// /// @brief the maximal body size //////////////////////////////////////////////////////////////////////////////// static size_t const MaximalBodySize; //////////////////////////////////////////////////////////////////////////////// /// @brief the maximal pipeline size //////////////////////////////////////////////////////////////////////////////// static size_t const MaximalPipelineSize; }; } } #endif // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- // Local Variables: // mode: outline-minor // outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}" // End: