/** * @file llcorehttpoprequest.h * @brief Internal declarations for the HttpOpRequest subclass * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef _LLCORE_HTTP_OPREQUEST_H_ #define _LLCORE_HTTP_OPREQUEST_H_ #include "openssl/x509_vfy.h" #include "openssl/ssl.h" #include "llcorehttpcommon.h" #include "llcorehttpheaders.h" #include "llcorehttpoperation.h" #include "llcorehttpoptions.h" #include "llcorehttprequest.h" #include "llcorerefcounted.h" #include "llerror.h" namespace LLCore { class BufferArray; // HttpOpRequest requests a supported HTTP method invocation with option and // header overrides. // // Essentially an RPC to get an HTTP GET, POST or PUT executed asynchronously // with options to override behaviors and HTTP headers. // // Constructor creates a raw object incapable of useful work. A subsequent call // to one of the setupXXX() methods provides the information needed to make a // working request which can then be enqueued to a request queue. class HttpOpRequest final : public HttpOperation { protected: LOG_CLASS(HttpOpRequest); public: typedef std::shared_ptr ptr_t; HttpOpRequest(); virtual ~HttpOpRequest(); // Use release() HttpOpRequest(const HttpOpRequest&) = delete; void operator=(const HttpOpRequest&) = delete; enum EMethod { HOR_GET, HOR_POST, HOR_PUT, HOR_DELETE, HOR_PATCH, HOR_COPY, HOR_MOVE }; virtual void stageFromRequest(HttpService*); virtual void stageFromReady(HttpService*); virtual void stageFromActive(HttpService*); virtual void visitNotifier(HttpRequest* request); public: // Setup Methods // // Basically an RPC setup for each type of HTTP method invocation with one // per method type. These are generally invoked right after construction. // // Threading: called by application thread // HttpStatus setupGet(HttpRequest::policy_t policy_id, const std::string& url, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id, const std::string& url, size_t offset, size_t len, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); HttpStatus setupPost(HttpRequest::policy_t policy_id, const std::string& url, BufferArray* body, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); HttpStatus setupPut(HttpRequest::policy_t policy_id, const std::string& url, BufferArray* body, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); HttpStatus setupDelete(HttpRequest::policy_t policy_id, const std::string& url, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); HttpStatus setupPatch(HttpRequest::policy_t policy_id, const std::string& url, BufferArray* body, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); HttpStatus setupCopy(HttpRequest::policy_t policy_id, const std::string& url, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); HttpStatus setupMove(HttpRequest::policy_t policy_id, const std::string& url, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); // Internal method used to setup the libcurl options for a request. // Does all the libcurl handle setup in one place. // // Threading: called by worker thread // HttpStatus prepareRequest(HttpService* service); virtual HttpStatus cancel(); protected: // Common setup for all the request methods. // // Threading: called by application thread // void setupCommon(HttpRequest::policy_t policy_id, const std::string& url, BufferArray* body, const HttpOptions::ptr_t& options, const HttpHeaders::ptr_t& headers); // libcurl operational callbacks // // Threading: called by worker thread // static size_t writeCallback(void* data, size_t size, size_t nmemb, void* userdata); static size_t readCallback(void* data, size_t size, size_t nmemb, void* userdata); static int seekCallback(void* data, curl_off_t offset, int origin); static size_t headerCallback(void* data, size_t size, size_t nmemb, void* userdata); static CURLcode curlSslCtxCallback(CURL* curl, void* ssl_ctx, void* userdata); static int sslCertVerifyCallback(X509_STORE_CTX* ctx, void* userdata); static int debugCallback(CURL*, curl_infotype info, char* buffer, size_t len, void* userdata); protected: unsigned int mProcFlags; static const unsigned int PF_SCAN_RANGE_HEADER = 0x00000001U; static const unsigned int PF_SAVE_HEADERS = 0x00000002U; static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U; HttpRequest::policyCallback_t mCallbackSSLVerify; public: // Request data EMethod mReqMethod; std::string mReqURL; BufferArray* mReqBody; off_t mReqOffset; size_t mReqLength; HttpHeaders::ptr_t mReqHeaders; HttpOptions::ptr_t mReqOptions; // Transport data bool mCurlActive; CURL* mCurlHandle; HttpService* mCurlService; curl_slist* mCurlHeaders; size_t mCurlBodyPos; char* mCurlTemp; // Scratch buffer for header processing size_t mCurlTempLen; // Result data HttpStatus mStatus; BufferArray* mReplyBody; off_t mReplyOffset; size_t mReplyLength; size_t mReplyFullLength; HttpHeaders::ptr_t mReplyHeaders; std::string mReplyConType; int mReplyRetryAfter; // Policy data int mPolicyRetries; int mPolicy503Retries; HttpTime mPolicyRetryAt; int mPolicyRetryLimit; // *HACK: some safe place to store any "location" header entry, that would // otherwise get mysteriously wiped out of mReplyHeaders between the // headerCallback() and the visitNotifier() calls... std::string mLocation; }; // --------------------------------------- // Free functions // --------------------------------------- // Internal function to append the contents of an HttpHeaders // instance to a curl_slist object. curl_slist* append_headers_to_slist(const HttpHeaders::ptr_t&, curl_slist* slist); } // End namespace LLCore #endif // _LLCORE_HTTP_OPREQUEST_H_