bool LLHTTPResponder::readLine( const LLChannelDescriptors& channels, buffer_ptr_t buffer, U8* dest, S32& len) { LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER); --len; U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len); dest[len] = '\0'; U8* newline = (U8*)strchr((char*)dest, '\n'); if(!newline) { if(len) { lldebugs << "readLine failed - too long maybe?" << llendl; markBad(channels, buffer); } return false; } S32 offset = -((len - 1) - (newline - dest)); ++newline; *newline = '\0'; mLastRead = buffer->seek(channels.in(), last, offset); return true; }
// 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; }
void buffer_object_t::test<1>() { LLChannelDescriptors channelDescriptors; ensure("in() and out() functions Failed", (0 == channelDescriptors.in() && 1 == channelDescriptors.out())); S32 val = 50; LLChannelDescriptors channelDescriptors1(val); ensure("LLChannelDescriptors in() and out() functions Failed", (50 == channelDescriptors1.in() && 51 == channelDescriptors1.out())); }
void buffer_object_t::test<6>() { LLBufferArray bufferArray; const char array[] = "SecondLife"; S32 len = strlen(array); LLChannelDescriptors channelDescriptors = bufferArray.nextChannel(); bufferArray.append(channelDescriptors.in(), (U8*)array, len); S32 count = bufferArray.countAfter(channelDescriptors.in(), NULL); ensure_equals("Appended size is:", count, len); }
// 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; }
void completedRaw( const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { completedHeader(); if (!isGoodStatus()) { if (getStatus() == HTTP_NOT_MODIFIED) { LL_INFOS("fsdata") << "Got [304] not modified for " << mURL << LL_ENDL; } else { LL_WARNS("fsdata") << "Error fetching " << mURL << " Status: [" << getStatus() << "]" << LL_ENDL; } return; } S32 data_size = buffer->countAfter(channels.in(), NULL); if (data_size <= 0) { LL_WARNS("fsdata") << "Received zero data for " << mURL << LL_ENDL; return; } U8* data = new U8[data_size]; buffer->readAfter(channels.in(), NULL, data, data_size); // basic check for valid data received LLXMLNodePtr xml_root; if ( (!LLXMLNode::parseBuffer(data, data_size, xml_root, NULL)) || (xml_root.isNull()) || (!xml_root->hasName("script_library")) ) { LL_WARNS("fsdata") << "Could not read the script library data from "<< mURL << LL_ENDL; delete[] data; data = NULL; return; } LLAPRFile outfile ; outfile.open(mFilename, LL_APR_WB); if (!outfile.getFileHandle()) { LL_WARNS("fsdata") << "Unable to open file for writing: " << mFilename << LL_ENDL; } else { LL_INFOS("fsdata") << "Saving " << mFilename << LL_ENDL; outfile.write(data, data_size); outfile.close() ; } delete[] data; data = NULL; }
void buffer_object_t::test<12>() { LLBufferArray bufferArray; LLChannelDescriptors channelDescriptors; LLBufferArray::segment_iterator_t it; S32 length = 1000; it = bufferArray.makeSegment(channelDescriptors.out(), length); ensure("makeSegment() function failed", (it != bufferArray.endSegment())); ensure("eraseSegment() function failed", bufferArray.eraseSegment(it)); ensure("eraseSegment() begin/end should now be same", bufferArray.beginSegment() == bufferArray.endSegment()); }
void buffer_object_t::test<9>() { LLBufferArray bufferArray; const char array[] = "SecondLife"; S32 len = strlen(array) + 1; std::string str(array); LLChannelDescriptors channelDescriptors = bufferArray.nextChannel(); bufferArray.append(channelDescriptors.in(), (U8*)array, len); LLBufferArray bufferArray1; ensure("Contents are not copied and the source buffer is not empty", (1 == bufferArray1.takeContents(bufferArray))); char buf[100]; S32 len2 = len; bufferArray1.readAfter(channelDescriptors.in(), NULL, (U8*)buf, len2); ensure_equals("takeContents failed to copy", buf, str); }
// 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; }
// virtual LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE); PUMP_DEBUG; // This pipe does not work if it does not have everyting. This // could be addressed by making a stream parser for llsd which // handled partial information. if(!eos) { return STATUS_BREAK; } PUMP_DEBUG; // we have everyting in the buffer, so turn the structure data rpc // response into an xml rpc response. LLBufferStream stream(channels, buffer.get()); stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER << std::flush; // Flush, or buffer->count() returns too much! LLSD sd; LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); PUMP_DEBUG; LLIOPipe::EStatus rv = STATUS_ERROR; if(sd.has("response")) { PUMP_DEBUG; // it is a normal response. pack it up and ship it out. stream.precision(DEFAULT_PRECISION); stream << XMLRPC_RESPONSE_HEADER; streamOut(stream, sd["response"]); stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER; rv = STATUS_DONE; } else if(sd.has("fault")) { PUMP_DEBUG; // it is a fault. stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger() << XMLRPC_FAULT_2 << xml_escape_string(sd["fault"]["description"].asString()) << XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER; rv = STATUS_DONE; } else { llwarns << "Unable to determine the type of LLSD response." << llendl; } PUMP_DEBUG; return rv; }
//virtual LLIOPipe::EStatus LLPipeStringInjector::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { buffer->append(channels.out(), (U8*) mString.data(), mString.size()); eos = true; return STATUS_DONE; }
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; } } } }
void buffer_object_t::test<8>() { LLBufferArray bufferArray; const char array[] = "SecondLife"; S32 len = strlen(array); const char array1[] = "LindenLabs"; S32 len1 = strlen(array1); std::string str(array); str.append(array1); LLChannelDescriptors channelDescriptors = bufferArray.nextChannel(); bufferArray.append(channelDescriptors.in(), (U8*)array, len); bufferArray.append(channelDescriptors.in(), (U8*)array1, len1); char buf[100]; S32 len2 = 20; bufferArray.readAfter(channelDescriptors.in(), NULL, (U8*)buf, len2); ensure_equals("readAfter length failed", len2, 20); buf[len2] = '\0'; ensure_equals("readAfter/append/append failed", buf, str); }
void HippoRestHandlerRaw::handle(int status, const std::string &reason, const LLChannelDescriptors &channels, const boost::shared_ptr<LLBufferArray> &body) { if (status == 200) { std::string data; LLBufferArray *buffer = body.get(); LLBufferArray::segment_iterator_t it, end = buffer->endSegment(); for (it=buffer->beginSegment(); it!=end; ++it) if (it->isOnChannel(channels.in())) data.append((char*)it->data(), it->size()); result(data); } else { llwarns << "Rest request error " << status << ": " << reason << llendl; } }
void HippoRestHandlerXml::handle(int status, const std::string &reason, const LLChannelDescriptors &channels, const boost::shared_ptr<LLBufferArray> &body) { if (status == 200) { LLXmlTree *tree = new LLXmlTree(); bool success = tree->parseBufferStart(); LLBufferArray *buffer = body.get(); LLBufferArray::segment_iterator_t it, end = buffer->endSegment(); for (it=buffer->beginSegment(); success && (it!=end); ++it) if (it->isOnChannel(channels.in())) success = success && tree->parseBuffer((char*)it->data(), it->size()); success = success && tree->parseBufferFinalize(); if (success) result(tree); delete tree; } else { llwarns << "Rest request error " << status << ": " << reason << llendl; } }
// virtual LLIOPipe::EStatus LLIOASCIIFuzz::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { while(mByteCount) { std::vector<U8> data; data.reserve(10000); int size = llmin(10000, mByteCount); std::generate_n( std::back_insert_iterator< std::vector<U8> >(data), size, random_ascii_generator()); buffer->append(channels.out(), &data[0], size); mByteCount -= size; } return STATUS_OK; }
// virtual LLIOPipe::EStatus LLSDRPCServer::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LLFastTimer t(FTM_PROCESS_SDRPC_SERVER); PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); // lldebugs << "LLSDRPCServer::process_impl" << llendl; // Once we have all the data, We need to read the sd on // the the in channel, and respond on the out channel if(!eos) return STATUS_BREAK; if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET; std::string method_name; LLIOPipe::EStatus status = STATUS_DONE; switch(mState) { case STATE_DEFERRED: PUMP_DEBUG; if(ESDRPCS_DONE != deferredResponse(channels, buffer.get())) { buildFault( channels, buffer.get(), FAULT_GENERIC, "deferred response failed."); } mState = STATE_DONE; return STATUS_DONE; case STATE_DONE: // lldebugs << "STATE_DONE" << llendl; break; case STATE_CALLBACK: // lldebugs << "STATE_CALLBACK" << llendl; PUMP_DEBUG; method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString(); if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME)) { if(ESDRPCS_DONE != callbackMethod( method_name, mRequest[LLSDRPC_PARAMETER_SD_NAME], channels, buffer.get())) { buildFault( channels, buffer.get(), FAULT_GENERIC, "Callback method call failed."); } } else { // this should never happen, since we should not be in // this state unless we originally found a method and // params during the first call to process. buildFault( channels, buffer.get(), FAULT_GENERIC, "Invalid LLSDRPC sever state - callback without method."); } pump->clearLock(mLock); mLock = 0; mState = STATE_DONE; break; case STATE_NONE: // lldebugs << "STATE_NONE" << llendl; default: { // First time we got here - process the SD request, and call // the method. PUMP_DEBUG; LLBufferStream istr(channels, buffer.get()); mRequest.clear(); LLSDSerialize::fromNotation( mRequest, istr, buffer->count(channels.in())); // { 'method':'...', 'parameter': ... } method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString(); if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME)) { ESDRPCSStatus rv = callMethod( method_name, mRequest[LLSDRPC_PARAMETER_SD_NAME], channels, buffer.get()); switch(rv) { case ESDRPCS_DEFERRED: mPump = pump; mLock = pump->setLock(); mState = STATE_DEFERRED; status = STATUS_BREAK; break; case ESDRPCS_CALLBACK: { mState = STATE_CALLBACK; LLPumpIO::LLLinkInfo link; link.mPipe = LLIOPipe::ptr_t(this); link.mChannels = channels; LLPumpIO::links_t links; links.push_back(link); pump->respond(links, buffer, context); mLock = pump->setLock(); status = STATUS_BREAK; break; } case ESDRPCS_DONE: mState = STATE_DONE; break; case ESDRPCS_ERROR: default: buildFault( channels, buffer.get(), FAULT_GENERIC, "Method call failed."); break; } } else { // send a fault buildFault( channels, buffer.get(), FAULT_GENERIC, "Unable to find method and parameter in request."); } break; } } PUMP_DEBUG; return status; }
// 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 LLIOSocketReader::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_READER); PUMP_DEBUG; if(!mSource) return STATUS_PRECONDITION_NOT_MET; if(!mInitialized) { PUMP_DEBUG; // Since the read will not block, it's ok to initialize and // attempt to read off the descriptor immediately. mInitialized = true; if(pump) { PUMP_DEBUG; LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketReader." << LL_ENDL; apr_pollfd_t poll_fd; poll_fd.p = NULL; poll_fd.desc_type = APR_POLL_SOCKET; poll_fd.reqevents = APR_POLLIN; poll_fd.rtnevents = 0x0; poll_fd.desc.s = mSource->getSocket(); poll_fd.client_data = NULL; pump->setConditional(this, &poll_fd); } } //if(!buffer) //{ // buffer = new LLBufferArray; //} PUMP_DEBUG; const apr_size_t READ_BUFFER_SIZE = 1024; char read_buf[READ_BUFFER_SIZE]; /*Flawfinder: ignore*/ apr_size_t len; apr_status_t status = APR_SUCCESS; do { PUMP_DEBUG; len = READ_BUFFER_SIZE; status = apr_socket_recv(mSource->getSocket(), read_buf, &len); buffer->append(channels.out(), (U8*)read_buf, len); } while((APR_SUCCESS == status) && (READ_BUFFER_SIZE == len)); LL_DEBUGS() << "socket read status: " << status << LL_ENDL; LLIOPipe::EStatus rv = STATUS_OK; PUMP_DEBUG; // *FIX: Also need to check for broken pipe if(APR_STATUS_IS_EOF(status)) { // *FIX: Should we shut down the socket read? if(pump) { pump->setConditional(this, NULL); } rv = STATUS_DONE; eos = true; } else if(APR_STATUS_IS_EAGAIN(status)) { /*Commented out by Aura 9-9-8 for DEV-19961. // everything is fine, but we can terminate this process pump. rv = STATUS_BREAK; */ } else { if(ll_apr_warn_status(status)) { rv = STATUS_ERROR; } } PUMP_DEBUG; return rv; }
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST); PUMP_DEBUG; if(!eos) return STATUS_BREAK; if(!buffer) return STATUS_ERROR; PUMP_DEBUG; // *FIX: This technique for reading data is far from optimal. We // need to have some kind of istream interface into the xml // parser... S32 bytes = buffer->countAfter(channels.in(), NULL); if(!bytes) return STATUS_ERROR; char* buf = new char[bytes + 1]; buf[bytes] = '\0'; buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); //lldebugs << "xmlrpc request: " << buf << llendl; // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if // values that are less than 0x20 are passed to it, except // 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage U8* cur_pBuf = (U8*)buf; U8 cur_char; for (S32 i=0; i<bytes; i++) { cur_char = *cur_pBuf; if ( cur_char < 0x20 && 0x09 != cur_char && 0x0a != cur_char && 0x0d != cur_char ) { *cur_pBuf = '?'; } ++cur_pBuf; } PUMP_DEBUG; XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML( buf, bytes, NULL); if(!request) { llwarns << "XML -> SD Request process parse error." << llendl; delete[] buf; return STATUS_ERROR; } PUMP_DEBUG; LLBufferStream stream(channels, buffer.get()); stream.precision(DEFAULT_PRECISION); const char* name = XMLRPC_RequestGetMethodName(request); stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "") << LLSDRPC_REQUEST_HEADER_2; XMLRPC_VALUE param = XMLRPC_RequestGetData(request); if(param) { PUMP_DEBUG; S32 size = XMLRPC_VectorSize(param); if(size > 1) { // if there are multiple parameters, stuff the values into // an array so that the next step in the chain can read them. stream << "["; } XMLRPC_VALUE current = XMLRPC_VectorRewind(param); bool needs_comma = false; while(current) { if(needs_comma) { stream << ","; } needs_comma = true; stream_out(stream, current); current = XMLRPC_VectorNext(param); } if(size > 1) { // close the array stream << "]"; } } stream << LLSDRPC_REQUEST_FOOTER << std::flush; XMLRPC_RequestFree(request, 1); delete[] buf; PUMP_DEBUG; return STATUS_DONE; }
LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE); PUMP_DEBUG; if(!eos) return STATUS_BREAK; if(!buffer) return STATUS_ERROR; PUMP_DEBUG; // *FIX: This technique for reading data is far from optimal. We // need to have some kind of istream interface into the xml // parser... S32 bytes = buffer->countAfter(channels.in(), NULL); if(!bytes) return STATUS_ERROR; char* buf = new char[bytes + 1]; buf[bytes] = '\0'; buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); //lldebugs << "xmlrpc response: " << buf << llendl; PUMP_DEBUG; XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML( buf, bytes, NULL); if(!response) { llwarns << "XML -> SD Response unable to parse xml." << llendl; delete[] buf; return STATUS_ERROR; } PUMP_DEBUG; LLBufferStream stream(channels, buffer.get()); stream.precision(DEFAULT_PRECISION); if(XMLRPC_ResponseIsFault(response)) { PUMP_DEBUG; stream << LLSDRPC_FAULT_HADER_1 << XMLRPC_GetResponseFaultCode(response) << LLSDRPC_FAULT_HADER_2; const char* fault_str = XMLRPC_GetResponseFaultString(response); std::string fault_string; if(fault_str) { fault_string.assign(fault_str); } stream << "'" << LLSDNotationFormatter::escapeString(fault_string) << "'" <<LLSDRPC_FAULT_FOOTER << std::flush; } else { PUMP_DEBUG; stream << LLSDRPC_RESPONSE_HEADER; XMLRPC_VALUE param = XMLRPC_RequestGetData(response); if(param) { stream_out(stream, param); } stream << LLSDRPC_RESPONSE_FOOTER << std::flush; } PUMP_DEBUG; XMLRPC_RequestFree(response, 1); delete[] buf; PUMP_DEBUG; return STATUS_DONE; }
// virtual LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST); // This pipe does not work if it does not have everyting. This // could be addressed by making a stream parser for llsd which // handled partial information. PUMP_DEBUG; if(!eos) { llinfos << "!eos" << llendl; return STATUS_BREAK; } // See if we can parse it LLBufferStream stream(channels, buffer.get()); LLSD sd; LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); if(stream.fail()) { llinfos << "STREAM FAILURE reading structure data." << llendl; } PUMP_DEBUG; // We can get the method and parameters from either the member // function or passed in via the buffer. We prefer the buffer if // we found a parameter and a method, or fall back to using // mMethod and putting everyting in the buffer into the parameter. std::string method; LLSD param_sd; if(sd.has("method") && sd.has("parameter")) { method = sd["method"].asString(); param_sd = sd["parameter"]; } else { method = mMethod; param_sd = sd; } if(method.empty()) { llwarns << "SD -> XML Request no method found." << llendl; return STATUS_ERROR; } PUMP_DEBUG; // We have a method, and some kind of parameter, so package it up // and send it out. LLBufferStream ostream(channels, buffer.get()); ostream.precision(DEFAULT_PRECISION); if(ostream.fail()) { llinfos << "STREAM FAILURE setting precision" << llendl; } ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1 << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2; if(ostream.fail()) { llinfos << "STREAM FAILURE writing method headers" << llendl; } switch(param_sd.type()) { case LLSD::TypeMap: // If the params are a map, then we do not want to iterate // through them since the iterators returned will be map // ordered un-named values, which will lose the names, and // only stream the values, turning it into an array. ostream << "<param>"; streamOut(ostream, param_sd); ostream << "</param>"; break; case LLSD::TypeArray: { LLSD::array_iterator it = param_sd.beginArray(); LLSD::array_iterator end = param_sd.endArray(); for(; it != end; ++it) { ostream << "<param>"; streamOut(ostream, *it); ostream << "</param>"; } break; } default: ostream << "<param>"; streamOut(ostream, param_sd); ostream << "</param>"; break; } stream << XMLRPC_REQUEST_FOOTER << std::flush; return STATUS_DONE; }
// static LLChannelDescriptors LLBufferArray::makeChannelConsumer( const LLChannelDescriptors& channels) { LLChannelDescriptors rv(channels.out()); return rv; }
void buffer_object_t::test<5>() { LLChannelDescriptors inchannelDescriptors(20); LLChannelDescriptors outchannelDescriptors = LLBufferArray::makeChannelConsumer(inchannelDescriptors); ensure("LLBufferArray::makeChannelConsumer() function Failed", (21 == outchannelDescriptors.in())); }
// virtual LLIOPipe::EStatus LLSDRPCClient::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) { PUMP_DEBUG; LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT); if((STATE_NONE == mState) || (!pump)) { // You should have called the call() method already. return STATUS_PRECONDITION_NOT_MET; } EStatus rv = STATUS_DONE; switch(mState) { case STATE_READY: { PUMP_DEBUG; // lldebugs << "LLSDRPCClient::process_impl STATE_READY" << llendl; buffer->append( channels.out(), (U8*)mRequest.c_str(), mRequest.length()); context[CONTEXT_DEST_URI_SD_LABEL] = mURI; mState = STATE_WAITING_FOR_RESPONSE; break; } case STATE_WAITING_FOR_RESPONSE: { PUMP_DEBUG; // The input channel has the sd response in it. //lldebugs << "LLSDRPCClient::process_impl STATE_WAITING_FOR_RESPONSE" // << llendl; LLBufferStream resp(channels, buffer.get()); LLSD sd; LLSDSerialize::fromNotation(sd, resp, buffer->count(channels.in())); LLSDRPCResponse* response = (LLSDRPCResponse*)mResponse.get(); if (!response) { mState = STATE_DONE; break; } response->extractResponse(sd); if(EPBQ_PROCESS == mQueue) { LLPumpIO::chain_t chain; chain.push_back(mResponse); pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS); } else { pump->respond(mResponse.get()); } mState = STATE_DONE; break; } case STATE_DONE: default: PUMP_DEBUG; llinfos << "invalid state to process" << llendl; rv = STATUS_ERROR; break; } return rv; }