~ubuntu-branches/ubuntu/quantal/aria2/quantal

« back to all changes in this revision

Viewing changes to src/HttpServerBodyCommand.cc

  • Committer: Bazaar Package Importer
  • Author(s): Kartik Mistry
  • Date: 2011-04-02 12:38:55 UTC
  • mfrom: (2.5.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110402123855-znkslovhf5qvkjut
Tags: 1.11.1-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
#include "HttpServerResponseCommand.h"
46
46
#include "OptionParser.h"
47
47
#include "OptionHandler.h"
48
 
#include "XmlRpcRequestProcessor.h"
49
 
#include "XmlRpcRequestParserStateMachine.h"
50
 
#include "XmlRpcMethod.h"
51
 
#include "XmlRpcMethodFactory.h"
52
 
#include "XmlRpcResponse.h"
53
48
#include "wallclock.h"
54
49
#include "util.h"
55
50
#include "fmt.h"
 
51
#include "SocketRecvBuffer.h"
 
52
#include "json.h"
 
53
#include "DlAbortEx.h"
 
54
#include "message.h"
 
55
#include "RpcMethod.h"
 
56
#include "RpcMethodFactory.h"
 
57
#include "RpcRequest.h"
 
58
#include "RpcResponse.h"
 
59
#ifdef ENABLE_XML_RPC
 
60
# include "XmlRpcRequestProcessor.h"
 
61
# include "XmlRpcRequestParserStateMachine.h"
 
62
#endif // ENABLE_XML_RPC
56
63
 
57
64
namespace aria2 {
58
65
 
66
73
    socket_(socket),
67
74
    httpServer_(httpServer)
68
75
{
 
76
  // To handle Content-Length == 0 case
69
77
  setStatus(Command::STATUS_ONESHOT_REALTIME);
70
78
  e_->addSocketForReadCheck(socket_, this);
 
79
  if(!httpServer_->getSocketRecvBuffer()->bufferEmpty()) {
 
80
    e_->setNoWait(true);
 
81
  }
71
82
}
72
83
 
73
84
HttpServerBodyCommand::~HttpServerBodyCommand()
75
86
  e_->deleteSocketForReadCheck(socket_, this);
76
87
}
77
88
 
 
89
namespace {
 
90
rpc::RpcResponse
 
91
createJsonRpcErrorResponse
 
92
(int code,
 
93
 const std::string& msg,
 
94
 const SharedHandle<ValueBase>& id)
 
95
{
 
96
  SharedHandle<Dict> params = Dict::g();
 
97
  params->put("code", Integer::g(code));
 
98
  params->put("message", msg);
 
99
  rpc::RpcResponse res(code, params, id);
 
100
  return res;
 
101
}
 
102
} // namespace
 
103
 
 
104
namespace {
 
105
std::string getJsonRpcContentType(bool script)
 
106
{
 
107
  return script ? "text/javascript" : "application/json-rpc";
 
108
}
 
109
} // namespace
 
110
 
 
111
void HttpServerBodyCommand::sendJsonRpcResponse
 
112
(const rpc::RpcResponse& res,
 
113
 const std::string& callback)
 
114
{
 
115
  bool gzip = httpServer_->supportsGZip();
 
116
  std::string responseData = res.toJson(callback, gzip);
 
117
  if(res.code == 0) {
 
118
    httpServer_->feedResponse(responseData,
 
119
                              getJsonRpcContentType(!callback.empty()));
 
120
  } else {
 
121
    httpServer_->disableKeepAlive();
 
122
    std::string httpCode;
 
123
    switch(res.code) {
 
124
    case -32600:
 
125
      httpCode = "400 Bad Request";
 
126
      break;
 
127
    case -32601:
 
128
      httpCode = "404 Not Found";
 
129
      break;
 
130
    default:
 
131
      httpCode = "500 Internal Server Error";
 
132
    };
 
133
    httpServer_->feedResponse(httpCode, A2STR::NIL,
 
134
                              responseData,
 
135
                              getJsonRpcContentType(!callback.empty()));
 
136
  }
 
137
  addHttpServerResponseCommand();
 
138
}
 
139
 
 
140
void HttpServerBodyCommand::sendJsonRpcBatchResponse
 
141
(const std::vector<rpc::RpcResponse>& results,
 
142
 const std::string& callback)
 
143
{
 
144
  bool gzip = httpServer_->supportsGZip();
 
145
  std::string responseData = rpc::toJsonBatch(results, callback, gzip);
 
146
  httpServer_->feedResponse(responseData,
 
147
                            getJsonRpcContentType(!callback.empty()));
 
148
  addHttpServerResponseCommand();
 
149
}
 
150
 
 
151
void HttpServerBodyCommand::addHttpServerResponseCommand()
 
152
{
 
153
  Command* command =
 
154
    new HttpServerResponseCommand(getCuid(), httpServer_, e_, socket_);
 
155
  e_->addCommand(command);
 
156
  e_->setNoWait(true);
 
157
}
 
158
 
 
159
rpc::RpcResponse
 
160
HttpServerBodyCommand::processJsonRpcRequest(const Dict* jsondict)
 
161
{
 
162
 
 
163
  SharedHandle<ValueBase> id = jsondict->get("id");
 
164
  if(!id) {
 
165
    return createJsonRpcErrorResponse(-32600, "Invalid Request.", Null::g());
 
166
  }
 
167
  const String* methodName = asString(jsondict->get("method"));
 
168
  if(!methodName) {
 
169
    return createJsonRpcErrorResponse(-32600, "Invalid Request.", id);
 
170
  }
 
171
  SharedHandle<List> params;
 
172
  const SharedHandle<ValueBase>& tempParams = jsondict->get("params");
 
173
  if(asList(tempParams)) {
 
174
    params = static_pointer_cast<List>(tempParams);
 
175
  } else if(!tempParams) {
 
176
    params = List::g();
 
177
  } else {
 
178
    // TODO No support for Named params
 
179
    return createJsonRpcErrorResponse(-32602, "Invalid params.", id);
 
180
  }
 
181
  rpc::RpcRequest req(methodName->s(), params, id);
 
182
  SharedHandle<rpc::RpcMethod> method;
 
183
  try {
 
184
    method = rpc::RpcMethodFactory::create(req.methodName);
 
185
  } catch(RecoverableException& e) {
 
186
    A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
 
187
    return createJsonRpcErrorResponse(-32601, "Method not found.", id);
 
188
  }
 
189
  method->setJsonRpc(true);
 
190
  rpc::RpcResponse res = method->execute(req, e_);
 
191
  return res;
 
192
}
 
193
 
78
194
bool HttpServerBodyCommand::execute()
79
195
{
80
196
  if(e_->getRequestGroupMan()->downloadFinished() || e_->isHaltRequested()) {
81
197
    return true;
82
198
  }
83
199
  try {
84
 
    if(socket_->isReadable(0) || httpServer_->getContentLength() == 0) {
 
200
    if(socket_->isReadable(0) ||
 
201
       !httpServer_->getSocketRecvBuffer()->bufferEmpty() ||
 
202
       httpServer_->getContentLength() == 0) {
85
203
      timeoutTimer_ = global::wallclock;
86
204
 
87
205
      if(httpServer_->receiveBody()) {
 
206
        std::string reqPath = httpServer_->getRequestPath();
 
207
        reqPath.erase(std::find(reqPath.begin(), reqPath.end(), '#'),
 
208
                      reqPath.end());
 
209
        std::string query(std::find(reqPath.begin(), reqPath.end(), '?'),
 
210
                          reqPath.end());
 
211
        reqPath.erase(reqPath.size()-query.size(), query.size());
88
212
        // Do something for requestpath and body
89
 
        if(httpServer_->getRequestPath() == "/rpc") {
90
 
          xmlrpc::XmlRpcRequest req =
91
 
            xmlrpc::XmlRpcRequestProcessor().parseMemory(httpServer_->getBody());
92
 
          
93
 
          SharedHandle<xmlrpc::XmlRpcMethod> method =
94
 
            xmlrpc::XmlRpcMethodFactory::create(req.methodName);
95
 
          xmlrpc::XmlRpcResponse res = method->execute(req, e_);
 
213
        if(reqPath == "/rpc") {
 
214
#ifdef ENABLE_XML_RPC
 
215
          rpc::RpcRequest req =
 
216
            rpc::XmlRpcRequestProcessor().parseMemory(httpServer_->getBody());
 
217
          SharedHandle<rpc::RpcMethod> method =
 
218
            rpc::RpcMethodFactory::create(req.methodName);
 
219
          rpc::RpcResponse res = method->execute(req, e_);
96
220
          bool gzip = httpServer_->supportsGZip();
97
221
          std::string responseData = res.toXml(gzip);
98
222
          httpServer_->feedResponse(responseData, "text/xml");
99
 
          Command* command =
100
 
            new HttpServerResponseCommand(getCuid(), httpServer_, e_, socket_);
101
 
          e_->addCommand(command);
102
 
          e_->setNoWait(true);
 
223
          addHttpServerResponseCommand();
 
224
#endif // ENABLE_XML_RPC
 
225
          return true;
 
226
        } else if(reqPath == "/jsonrpc") {
 
227
          std::string callback;
 
228
          SharedHandle<ValueBase> json;
 
229
          try {
 
230
            if(httpServer_->getMethod() == "GET") {
 
231
              json::JsonGetParam param = json::decodeGetParams(query);
 
232
              callback = param.callback;
 
233
              json = json::decode(param.request);
 
234
            } else {
 
235
              json = json::decode(httpServer_->getBody());
 
236
            }
 
237
          } catch(RecoverableException& e) {
 
238
            A2_LOG_INFO_EX
 
239
              (fmt("CUID#%lld - Failed to parse JSON-RPC request",
 
240
                   getCuid()),
 
241
               e);
 
242
            rpc::RpcResponse res
 
243
              (createJsonRpcErrorResponse(-32700, "Parse error.", Null::g()));
 
244
            sendJsonRpcResponse(res, callback);
 
245
            return true;
 
246
          }
 
247
          const Dict* jsondict = asDict(json);
 
248
          if(jsondict) {
 
249
            rpc::RpcResponse res = processJsonRpcRequest(jsondict);
 
250
            sendJsonRpcResponse(res, callback);
 
251
          } else {
 
252
            const List* jsonlist = asList(json);
 
253
            if(jsonlist) {
 
254
              // This is batch call
 
255
              std::vector<rpc::RpcResponse> results;
 
256
              for(List::ValueType::const_iterator i = jsonlist->begin(),
 
257
                    eoi = jsonlist->end(); i != eoi; ++i) {
 
258
                const Dict* jsondict = asDict(*i);
 
259
                if(jsondict) {
 
260
                  rpc::RpcResponse r = processJsonRpcRequest(jsondict);
 
261
                  results.push_back(r);
 
262
                }
 
263
              }
 
264
              sendJsonRpcBatchResponse(results, callback);
 
265
            } else {
 
266
              rpc::RpcResponse res
 
267
                (createJsonRpcErrorResponse
 
268
                 (-32600, "Invalid Request.", Null::g()));
 
269
              sendJsonRpcResponse(res, callback);
 
270
            }
 
271
          }
103
272
          return true;
104
273
        } else {
105
274
          return true;