Master Core  v0.0.9 - 49a5c0d97abf09ef2911ddfe8d9551df59f9efd3-dirty
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
rpcprotocol.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "rpcprotocol.h"
7 
8 #include "util.h"
9 
10 #include <stdint.h>
11 
12 #include <boost/algorithm/string.hpp>
13 #include <boost/asio.hpp>
14 #include <boost/asio/ssl.hpp>
15 #include <boost/bind.hpp>
16 #include <boost/filesystem.hpp>
17 #include <boost/foreach.hpp>
18 #include <boost/iostreams/concepts.hpp>
19 #include <boost/iostreams/stream.hpp>
20 #include <boost/shared_ptr.hpp>
21 #include "json/json_spirit_writer_template.h"
22 
23 using namespace std;
24 using namespace boost;
25 using namespace boost::asio;
26 using namespace json_spirit;
27 
28 //
29 // HTTP protocol
30 //
31 // This ain't Apache. We're just using HTTP header for the length field
32 // and to be compatible with other JSON-RPC implementations.
33 //
34 
35 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
36 {
37  ostringstream s;
38  s << "POST / HTTP/1.1\r\n"
39  << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
40  << "Host: 127.0.0.1\r\n"
41  << "Content-Type: application/json\r\n"
42  << "Content-Length: " << strMsg.size() << "\r\n"
43  << "Connection: close\r\n"
44  << "Accept: application/json\r\n";
45  BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
46  s << item.first << ": " << item.second << "\r\n";
47  s << "\r\n" << strMsg;
48 
49  return s.str();
50 }
51 
52 static string rfc1123Time()
53 {
54  return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
55 }
56 
57 string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
58 {
59  if (nStatus == HTTP_UNAUTHORIZED)
60  return strprintf("HTTP/1.0 401 Authorization Required\r\n"
61  "Date: %s\r\n"
62  "Server: bitcoin-json-rpc/%s\r\n"
63  "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
64  "Content-Type: text/html\r\n"
65  "Content-Length: 296\r\n"
66  "\r\n"
67  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
68  "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
69  "<HTML>\r\n"
70  "<HEAD>\r\n"
71  "<TITLE>Error</TITLE>\r\n"
72  "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
73  "</HEAD>\r\n"
74  "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
75  "</HTML>\r\n", rfc1123Time(), FormatFullVersion());
76  const char *cStatus;
77  if (nStatus == HTTP_OK) cStatus = "OK";
78  else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
79  else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
80  else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
81  else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
82  else cStatus = "";
83  return strprintf(
84  "HTTP/1.1 %d %s\r\n"
85  "Date: %s\r\n"
86  "Connection: %s\r\n"
87  "Content-Length: %u\r\n"
88  "Content-Type: application/json\r\n"
89  "Server: bitcoin-json-rpc/%s\r\n"
90  "\r\n"
91  "%s",
92  nStatus,
93  cStatus,
94  rfc1123Time(),
95  keepalive ? "keep-alive" : "close",
96  strMsg.size(),
98  strMsg);
99 }
100 
101 bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
102  string& http_method, string& http_uri)
103 {
104  string str;
105  getline(stream, str);
106 
107  // HTTP request line is space-delimited
108  vector<string> vWords;
109  boost::split(vWords, str, boost::is_any_of(" "));
110  if (vWords.size() < 2)
111  return false;
112 
113  // HTTP methods permitted: GET, POST
114  http_method = vWords[0];
115  if (http_method != "GET" && http_method != "POST")
116  return false;
117 
118  // HTTP URI must be an absolute path, relative to current host
119  http_uri = vWords[1];
120  if (http_uri.size() == 0 || http_uri[0] != '/')
121  return false;
122 
123  // parse proto, if present
124  string strProto = "";
125  if (vWords.size() > 2)
126  strProto = vWords[2];
127 
128  proto = 0;
129  const char *ver = strstr(strProto.c_str(), "HTTP/1.");
130  if (ver != NULL)
131  proto = atoi(ver+7);
132 
133  return true;
134 }
135 
136 int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
137 {
138  string str;
139  getline(stream, str);
140  vector<string> vWords;
141  boost::split(vWords, str, boost::is_any_of(" "));
142  if (vWords.size() < 2)
144  proto = 0;
145  const char *ver = strstr(str.c_str(), "HTTP/1.");
146  if (ver != NULL)
147  proto = atoi(ver+7);
148  return atoi(vWords[1].c_str());
149 }
150 
151 int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
152 {
153  int nLen = 0;
154  while (true)
155  {
156  string str;
157  std::getline(stream, str);
158  if (str.empty() || str == "\r")
159  break;
160  string::size_type nColon = str.find(":");
161  if (nColon != string::npos)
162  {
163  string strHeader = str.substr(0, nColon);
164  boost::trim(strHeader);
165  boost::to_lower(strHeader);
166  string strValue = str.substr(nColon+1);
167  boost::trim(strValue);
168  mapHeadersRet[strHeader] = strValue;
169  if (strHeader == "content-length")
170  nLen = atoi(strValue.c_str());
171  }
172  }
173  return nLen;
174 }
175 
176 
177 int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
178  string>& mapHeadersRet, string& strMessageRet,
179  int nProto)
180 {
181  mapHeadersRet.clear();
182  strMessageRet = "";
183 
184  // Read header
185  int nLen = ReadHTTPHeaders(stream, mapHeadersRet);
186  if (nLen < 0 || nLen > (int)MAX_SIZE)
188 
189  // Read message
190  if (nLen > 0)
191  {
192  vector<char> vch(nLen);
193  stream.read(&vch[0], nLen);
194  strMessageRet = string(vch.begin(), vch.end());
195  }
196 
197  string sConHdr = mapHeadersRet["connection"];
198 
199  if ((sConHdr != "close") && (sConHdr != "keep-alive"))
200  {
201  if (nProto >= 1)
202  mapHeadersRet["connection"] = "keep-alive";
203  else
204  mapHeadersRet["connection"] = "close";
205  }
206 
207  return HTTP_OK;
208 }
209 
210 //
211 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
212 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
213 // unspecified (HTTP errors and contents of 'error').
214 //
215 // 1.0 spec: http://json-rpc.org/wiki/specification
216 // 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
217 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
218 //
219 
220 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
221 {
222  Object request;
223  request.push_back(Pair("method", strMethod));
224  request.push_back(Pair("params", params));
225  request.push_back(Pair("id", id));
226  return write_string(Value(request), false) + "\n";
227 }
228 
229 Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
230 {
231  Object reply;
232  if (error.type() != null_type)
233  reply.push_back(Pair("result", Value::null));
234  else
235  reply.push_back(Pair("result", result));
236  reply.push_back(Pair("error", error));
237  reply.push_back(Pair("id", id));
238  return reply;
239 }
240 
241 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
242 {
243  Object reply = JSONRPCReplyObj(result, error, id);
244  return write_string(Value(reply), false) + "\n";
245 }
246 
247 Object JSONRPCError(int code, const string& message)
248 {
249  Object error;
250  error.push_back(Pair("code", code));
251  error.push_back(Pair("message", message));
252  return error;
253 }
int ReadHTTPStatus(std::basic_istream< char > &stream, int &proto)
string JSONRPCReply(const Value &result, const Value &error, const Value &id)
Definition: init.h:13
#define PAIRTYPE(t1, t2)
Definition: util.h:48
bool ReadHTTPRequestLine(std::basic_istream< char > &stream, int &proto, string &http_method, string &http_uri)
#define strprintf
Definition: util.h:116
STL namespace.
Object JSONRPCError(int code, const string &message)
std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime)
Definition: util.cpp:1429
int ReadHTTPMessage(std::basic_istream< char > &stream, map< string, string > &mapHeadersRet, string &strMessageRet, int nProto)
static bool error(const char *format)
Definition: util.h:148
string HTTPReply(int nStatus, const string &strMsg, bool keepalive)
Definition: rpcprotocol.cpp:57
int64_t GetTime()
Definition: util.cpp:1215
static string rfc1123Time()
Definition: rpcprotocol.cpp:52
Object JSONRPCReplyObj(const Value &result, const Value &error, const Value &id)
static const unsigned int MAX_SIZE
Definition: serialize.h:30
string FormatFullVersion()
Definition: util.cpp:1325
string HTTPPost(const string &strMsg, const map< string, string > &mapRequestHeaders)
Definition: rpcprotocol.cpp:35
int ReadHTTPHeaders(std::basic_istream< char > &stream, map< string, string > &mapHeadersRet)
string JSONRPCRequest(const string &strMethod, const Array &params, const Value &id)
int atoi(const std::string &str)
Definition: util.h:242