// virtual LLIOPipe::EStatus LLContextURLExtractor::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); // The destination host is in the context. if(context.isUndefined() || !mRequest) { return STATUS_PRECONDITION_NOT_MET; } // copy in to out, since this just extract the URL and does not // actually change the data. LLChangeChannel change(channels.in(), channels.out()); std::for_each(buffer->beginSegment(), buffer->endSegment(), change); // find the context url if(context.has(CONTEXT_DEST_URI_SD_LABEL)) { mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL].asString()); return STATUS_DONE; } return STATUS_ERROR; }
// virtual LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER); if(eos) { PUMP_DEBUG; //mGotEOS = true; std::ostringstream ostr; std::string message = context[CONTEXT_RESPONSE]["statusMessage"]; int code = context[CONTEXT_RESPONSE]["statusCode"]; if (code < 200) { code = 200; message = "OK"; } ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n"; S32 content_length = buffer->countAfter(channels.in(), NULL); if(0 < content_length) { ostr << "Content-Length: " << content_length << "\r\n"; } // *NOTE: This guard can go away once the LLSD static map // iterator is available. Phoenix. 2008-05-09 LLSD headers = context[CONTEXT_RESPONSE][CONTEXT_HEADERS]; if(headers.isDefined()) { LLSD::map_iterator iter = headers.beginMap(); LLSD::map_iterator end = headers.endMap(); for(; iter != end; ++iter) { ostr << (*iter).first << ": " << (*iter).second.asString() << "\r\n"; } } ostr << "\r\n"; LLChangeChannel change(channels.in(), channels.out()); std::for_each(buffer->beginSegment(), buffer->endSegment(), change); std::string header = ostr.str(); buffer->prepend(channels.out(), (U8*)header.c_str(), header.size()); PUMP_DEBUG; return STATUS_DONE; } PUMP_DEBUG; return STATUS_OK; }
// virtual LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER); if(eos) { PUMP_DEBUG; //mGotEOS = true; std::ostringstream ostr; std::string message = context["response"]["statusMessage"]; int code = context["response"]["statusCode"]; if (code < 200) { code = 200; message = "OK"; } ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n"; std::string type = context["response"]["contentType"].asString(); if (!type.empty()) { ostr << "Content-Type: " << type << "\r\n"; } S32 content_length = buffer->countAfter(channels.in(), NULL); if(0 < content_length) { ostr << "Content-Length: " << content_length << "\r\n"; } ostr << "\r\n"; LLChangeChannel change(channels.in(), channels.out()); std::for_each(buffer->beginSegment(), buffer->endSegment(), change); std::string header = ostr.str(); buffer->prepend(channels.out(), (U8*)header.c_str(), header.size()); PUMP_DEBUG; return STATUS_DONE; } PUMP_DEBUG; return STATUS_OK; }
void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { if (mCode == CURLE_OK && !is_internal_http_error(status)) { mBufferSize = buffer->count(channels.in()); if (200 <= status && status < 400) { char* ptr = NULL; char* buf = NULL; LLMutexLock lock(buffer->getMutex()); LLBufferArray::const_segment_iterator_t const end = buffer->endSegment(); for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter) { LLSegment const& segment = *iter; if (segment.isOnChannel(channels.in())) { S32 const segment_size = segment.size(); if (!buf) { if (segment_size == mBufferSize) { // It's contiguous, no need for copying. mResponse = XMLRPC_REQUEST_FromXML((char const*)segment.data(), mBufferSize, NULL); break; } ptr = buf = new char [mBufferSize]; } llassert(ptr + segment_size <= buf + mBufferSize); memcpy(ptr, segment.data(), segment_size); ptr += segment_size; } } if (buf) { mResponse = XMLRPC_REQUEST_FromXML(buf, mBufferSize, NULL); delete [] buf; } } } }
// virtual LLIOPipe::EStatus LLIOSocketWriter::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_WRITER); PUMP_DEBUG; if(!mDestination) return STATUS_PRECONDITION_NOT_MET; if(!mInitialized) { PUMP_DEBUG; // Since the write will not block, it's ok to initialize and // attempt to write immediately. mInitialized = true; if(pump) { PUMP_DEBUG; LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketWriter." << LL_ENDL; apr_pollfd_t poll_fd; poll_fd.p = NULL; poll_fd.desc_type = APR_POLL_SOCKET; poll_fd.reqevents = APR_POLLOUT; poll_fd.rtnevents = 0x0; poll_fd.desc.s = mDestination->getSocket(); poll_fd.client_data = NULL; pump->setConditional(this, &poll_fd); } } PUMP_DEBUG; // *FIX: Some sort of writev implementation would be much more // efficient - not only because writev() is better, but also // because we won't have to do as much work to find the start // address. buffer->lock(); LLBufferArray::segment_iterator_t it; LLBufferArray::segment_iterator_t end = buffer->endSegment(); LLSegment segment; it = buffer->constructSegmentAfter(mLastWritten, segment); /* if(NULL == mLastWritten) { it = buffer->beginSegment(); segment = (*it); } else { it = buffer->getSegment(mLastWritten); segment = (*it); S32 size = segment.size(); U8* data = segment.data(); if((data + size) == mLastWritten) { ++it; segment = (*it); } else { // *FIX: check the math on this one segment = LLSegment( (*it).getChannelMask(), mLastWritten + 1, size - (mLastWritten - data)); } } */ PUMP_DEBUG; apr_size_t len; bool done = false; apr_status_t status = APR_SUCCESS; while(it != end) { PUMP_DEBUG; if((*it).isOnChannel(channels.in())) { PUMP_DEBUG; len = (apr_size_t)segment.size(); status = apr_socket_send( mDestination->getSocket(), (const char*)segment.data(), &len); // We sometimes get a 'non-blocking socket operation could not be // completed immediately' error from apr_socket_send. In this // case we break and the data will be sent the next time the chain // is pumped. if(APR_STATUS_IS_EAGAIN(status)) { ll_apr_warn_status(status); break; } mLastWritten = segment.data() + len - 1; PUMP_DEBUG; if((S32)len < segment.size()) { break; } } ++it; if(it != end) { segment = (*it); } else { done = true; } } buffer->unlock(); PUMP_DEBUG; if(done && eos) { return STATUS_DONE; } return STATUS_OK; }
// virtual LLIOPipe::EStatus LLHTTPResponder::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER); LLIOPipe::EStatus status = STATUS_OK; // parsing headers if((STATE_NOTHING == mState) || (STATE_READING_HEADERS == mState)) { PUMP_DEBUG; status = STATUS_BREAK; mState = STATE_READING_HEADERS; const S32 HEADER_BUFFER_SIZE = 1024; char buf[HEADER_BUFFER_SIZE + 1]; /*Flawfinder: ignore*/ S32 len = HEADER_BUFFER_SIZE; #if 0 if(true) { LLBufferArray::segment_iterator_t seg_iter = buffer->beginSegment(); char buf[1024]; /*Flawfinder: ignore*/ while(seg_iter != buffer->endSegment()) { memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/ buf[(*seg_iter).size()] = '\0'; llinfos << (*seg_iter).getChannel() << ": " << buf << llendl; ++seg_iter; } } #endif PUMP_DEBUG; if(readLine(channels, buffer, (U8*)buf, len)) { bool read_next_line = false; bool parse_all = true; if(mVerb.empty()) { read_next_line = true; LLMemoryStream header((U8*)buf, len); header >> mVerb; if((HTTP_VERB_GET == mVerb) || (HTTP_VERB_POST == mVerb) || (HTTP_VERB_PUT == mVerb) || (HTTP_VERB_DELETE == mVerb)) { header >> mAbsPathAndQuery; header >> mVersion; lldebugs << "http request: " << mVerb << " " << mAbsPathAndQuery << " " << mVersion << llendl; std::string::size_type delimiter = mAbsPathAndQuery.find('?'); if (delimiter == std::string::npos) { mPath = mAbsPathAndQuery; mQuery = ""; } else { mPath = mAbsPathAndQuery.substr(0, delimiter); mQuery = mAbsPathAndQuery.substr(delimiter+1); } if(!mAbsPathAndQuery.empty()) { if(mVersion.empty()) { // simple request. parse_all = false; mState = STATE_DONE; mVersion.assign("HTTP/1.0"); } } }