// 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; }
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 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 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; }
// 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; }