/** * @file httprequest.cpp * @brief Implementation of the HTTPRequest class * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012-2013, 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$ */ #include "httprequest.h" #include "_httprequestqueue.h" #include "_httpreplyqueue.h" #include "_httpservice.h" #include "_httppolicy.h" #include "_httpoperation.h" #include "_httpoprequest.h" #include "_httpopsetpriority.h" #include "_httpopcancel.h" #include "_httpopsetget.h" #include "lltimer.h" namespace { bool has_inited(false); } namespace LLCore { // ==================================== // HttpRequest Implementation // ==================================== HttpRequest::HttpRequest() : mReplyQueue(NULL), mRequestQueue(NULL) { mRequestQueue = HttpRequestQueue::instanceOf(); mRequestQueue->addRef(); mReplyQueue = new HttpReplyQueue(); } HttpRequest::~HttpRequest() { if (mRequestQueue) { mRequestQueue->release(); mRequestQueue = NULL; } if (mReplyQueue) { mReplyQueue->release(); mReplyQueue = NULL; } } // ==================================== // Policy Methods // ==================================== HttpRequest::policy_t HttpRequest::createPolicyClass() { if (HttpService::RUNNING == HttpService::instanceOf()->getState()) { return 0; } return HttpService::instanceOf()->createPolicyClass(); } HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, long value, long * ret_value) { if (HttpService::RUNNING == HttpService::instanceOf()->getState()) { return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); } return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); } HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value, std::string * ret_value) { if (HttpService::RUNNING == HttpService::instanceOf()->getState()) { return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); } return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); } HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, policyCallback_t value, policyCallback_t * ret_value) { if (HttpService::RUNNING == HttpService::instanceOf()->getState()) { return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); } return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); } HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass, long value, HttpHandler * handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpSetGet * op = new HttpOpSetGet(); if (! (status = op->setupSet(opt, pclass, value))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass, const std::string & value, HttpHandler * handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpSetGet * op = new HttpOpSetGet(); if (! (status = op->setupSet(opt, pclass, value))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } // ==================================== // Request Methods // ==================================== HttpStatus HttpRequest::getStatus() const { return mLastReqStatus; } HttpHandle HttpRequest::requestGet(policy_t policy_id, priority_t priority, const std::string & url, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (! (status = op->setupGet(policy_id, priority, url, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id, priority_t priority, const std::string & url, size_t offset, size_t len, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (! (status = op->setupGetByteRange(policy_id, priority, url, offset, len, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestPost(policy_t policy_id, priority_t priority, const std::string & url, BufferArray * body, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (! (status = op->setupPost(policy_id, priority, url, body, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestPut(policy_t policy_id, priority_t priority, const std::string & url, BufferArray * body, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (! (status = op->setupPut(policy_id, priority, url, body, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestDelete(policy_t policy_id, priority_t priority, const std::string & url, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (!(status = op->setupDelete(policy_id, priority, url, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (!(status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestPatch(policy_t policy_id, priority_t priority, const std::string & url, BufferArray * body, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (!(status = op->setupPatch(policy_id, priority, url, body, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (!(status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestCopy(policy_t policy_id, priority_t priority, const std::string & url, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (!(status = op->setupCopy(policy_id, priority, url, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (!(status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestMove(policy_t policy_id, priority_t priority, const std::string & url, const HttpOptions::ptr_t & options, const HttpHeaders::ptr_t & headers, HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpRequest * op = new HttpOpRequest(); if (!(status = op->setupMove(policy_id, priority, url, options, headers))) { op->release(); mLastReqStatus = status; return handle; } op->setReplyPath(mReplyQueue, user_handler); if (!(status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpNull * op = new HttpOpNull(); op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpStatus HttpRequest::update(long usecs) { HttpOperation * op(NULL); if (usecs) { const HttpTime limit(totalTime() + HttpTime(usecs)); while (limit >= totalTime() && (op = mReplyQueue->fetchOp())) { // Process operation op->visitNotifier(this); // We're done with the operation op->release(); } } else { // Same as above, just no time limit HttpReplyQueue::OpContainer replies; mReplyQueue->fetchAll(replies); if (! replies.empty()) { for (HttpReplyQueue::OpContainer::iterator iter(replies.begin()); replies.end() != iter; ++iter) { // Swap op pointer for NULL; op = *iter; *iter = NULL; // Process operation op->visitNotifier(this); // We're done with the operation op->release(); } } } return HttpStatus(); } // ==================================== // Request Management Methods // ==================================== HttpHandle HttpRequest::requestCancel(HttpHandle request, HttpHandler * user_handler) { HttpStatus status; HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpCancel * op = new HttpOpCancel(request); op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return ret_handle; } mLastReqStatus = status; ret_handle = static_cast(op); return ret_handle; } HttpHandle HttpRequest::requestSetPriority(HttpHandle request, priority_t priority, HttpHandler * handler) { HttpStatus status; HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpSetPriority * op = new HttpOpSetPriority(request, priority); op->setReplyPath(mReplyQueue, handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return ret_handle; } mLastReqStatus = status; ret_handle = static_cast(op); return ret_handle; } // ==================================== // Utility Methods // ==================================== HttpStatus HttpRequest::createService() { HttpStatus status; if (! has_inited) { HttpRequestQueue::init(); HttpRequestQueue * rq = HttpRequestQueue::instanceOf(); HttpService::init(rq); has_inited = true; } return status; } HttpStatus HttpRequest::destroyService() { HttpStatus status; if (has_inited) { HttpService::term(); HttpRequestQueue::term(); has_inited = false; } return status; } HttpStatus HttpRequest::startThread() { HttpStatus status; HttpService::instanceOf()->startThread(); return status; } HttpHandle HttpRequest::requestStopThread(HttpHandler * user_handler) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpStop * op = new HttpOpStop(); op->setReplyPath(mReplyQueue, user_handler); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } HttpHandle HttpRequest::requestSpin(int mode) { HttpStatus status; HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); HttpOpSpin * op = new HttpOpSpin(mode); op->setReplyPath(mReplyQueue, NULL); if (! (status = mRequestQueue->addOp(op))) // transfers refcount { op->release(); mLastReqStatus = status; return handle; } mLastReqStatus = status; handle = static_cast(op); return handle; } } // end namespace LLCore