]> Git Repo - VerusCoin.git/blame - src/rpcprotocol.cpp
test
[VerusCoin.git] / src / rpcprotocol.cpp
CommitLineData
fb78cc23 1// Copyright (c) 2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2014 The Bitcoin Core developers
72fb3d29 3// Distributed under the MIT software license, see the accompanying
fb78cc23
WL
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include "rpcprotocol.h"
7
71697f97 8#include "clientversion.h"
ad49c256 9#include "tinyformat.h"
611116d4 10#include "util.h"
ad49c256
WL
11#include "utilstrencodings.h"
12#include "utiltime.h"
6e5fd003 13#include "version.h"
fb78cc23
WL
14
15#include <stdint.h>
16
17#include <boost/algorithm/string.hpp>
18#include <boost/asio.hpp>
19#include <boost/asio/ssl.hpp>
20#include <boost/bind.hpp>
21#include <boost/filesystem.hpp>
22#include <boost/foreach.hpp>
23#include <boost/iostreams/concepts.hpp>
24#include <boost/iostreams/stream.hpp>
fb78cc23
WL
25#include <boost/shared_ptr.hpp>
26#include "json/json_spirit_writer_template.h"
27
28using namespace std;
fb78cc23
WL
29using namespace json_spirit;
30
72fb3d29 31//! Number of bytes to allocate and read at most at once in post data
2ec5a3d2
WL
32const size_t POST_READ_SIZE = 256 * 1024;
33
72fb3d29
MF
34/**
35 * HTTP protocol
36 *
37 * This ain't Apache. We're just using HTTP header for the length field
38 * and to be compatible with other JSON-RPC implementations.
39 */
fb78cc23
WL
40
41string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
42{
43 ostringstream s;
44 s << "POST / HTTP/1.1\r\n"
45 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
46 << "Host: 127.0.0.1\r\n"
47 << "Content-Type: application/json\r\n"
48 << "Content-Length: " << strMsg.size() << "\r\n"
49 << "Connection: close\r\n"
50 << "Accept: application/json\r\n";
51 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
52 s << item.first << ": " << item.second << "\r\n";
53 s << "\r\n" << strMsg;
54
55 return s.str();
56}
57
58static string rfc1123Time()
59{
3e8ac6af 60 return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
fb78cc23
WL
61}
62
16f33f16 63static const char *httpStatusDescription(int nStatus)
64{
65 switch (nStatus) {
66 case HTTP_OK: return "OK";
67 case HTTP_BAD_REQUEST: return "Bad Request";
68 case HTTP_FORBIDDEN: return "Forbidden";
69 case HTTP_NOT_FOUND: return "Not Found";
70 case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
71 default: return "";
72 }
73}
74
75string HTTPError(int nStatus, bool keepalive, bool headersOnly)
fb78cc23
WL
76{
77 if (nStatus == HTTP_UNAUTHORIZED)
78 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
79 "Date: %s\r\n"
80 "Server: bitcoin-json-rpc/%s\r\n"
81 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
82 "Content-Type: text/html\r\n"
83 "Content-Length: 296\r\n"
84 "\r\n"
85 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
86 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
87 "<HTML>\r\n"
88 "<HEAD>\r\n"
89 "<TITLE>Error</TITLE>\r\n"
90 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
91 "</HEAD>\r\n"
92 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
7d9d134b 93 "</HTML>\r\n", rfc1123Time(), FormatFullVersion());
c912e22d 94
16f33f16 95 return HTTPReply(nStatus, httpStatusDescription(nStatus), keepalive,
96 headersOnly, "text/plain");
97}
c912e22d 98
e17151ad 99string HTTPReplyHeader(int nStatus, bool keepalive, size_t contentLength, const char *contentType)
16f33f16 100{
fb78cc23
WL
101 return strprintf(
102 "HTTP/1.1 %d %s\r\n"
103 "Date: %s\r\n"
104 "Connection: %s\r\n"
783b182c 105 "Content-Length: %u\r\n"
c912e22d 106 "Content-Type: %s\r\n"
fb78cc23 107 "Server: bitcoin-json-rpc/%s\r\n"
e17151ad 108 "\r\n",
fb78cc23 109 nStatus,
16f33f16 110 httpStatusDescription(nStatus),
7d9d134b 111 rfc1123Time(),
fb78cc23 112 keepalive ? "keep-alive" : "close",
e17151ad 113 contentLength,
c912e22d 114 contentType,
e17151ad
WL
115 FormatFullVersion());
116}
117
118string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
119 bool headersOnly, const char *contentType)
120{
121 if (headersOnly)
122 {
123 return HTTPReplyHeader(nStatus, keepalive, 0, contentType);
124 } else {
125 return HTTPReplyHeader(nStatus, keepalive, strMsg.size(), contentType) + strMsg;
126 }
fb78cc23
WL
127}
128
129bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
130 string& http_method, string& http_uri)
131{
132 string str;
133 getline(stream, str);
134
135 // HTTP request line is space-delimited
136 vector<string> vWords;
137 boost::split(vWords, str, boost::is_any_of(" "));
138 if (vWords.size() < 2)
139 return false;
140
141 // HTTP methods permitted: GET, POST
142 http_method = vWords[0];
143 if (http_method != "GET" && http_method != "POST")
144 return false;
145
146 // HTTP URI must be an absolute path, relative to current host
147 http_uri = vWords[1];
148 if (http_uri.size() == 0 || http_uri[0] != '/')
149 return false;
150
151 // parse proto, if present
152 string strProto = "";
153 if (vWords.size() > 2)
154 strProto = vWords[2];
155
156 proto = 0;
157 const char *ver = strstr(strProto.c_str(), "HTTP/1.");
158 if (ver != NULL)
159 proto = atoi(ver+7);
160
161 return true;
162}
163
164int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
165{
166 string str;
167 getline(stream, str);
168 vector<string> vWords;
169 boost::split(vWords, str, boost::is_any_of(" "));
170 if (vWords.size() < 2)
171 return HTTP_INTERNAL_SERVER_ERROR;
172 proto = 0;
173 const char *ver = strstr(str.c_str(), "HTTP/1.");
174 if (ver != NULL)
175 proto = atoi(ver+7);
176 return atoi(vWords[1].c_str());
177}
178
179int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
180{
181 int nLen = 0;
182 while (true)
183 {
184 string str;
185 std::getline(stream, str);
186 if (str.empty() || str == "\r")
187 break;
188 string::size_type nColon = str.find(":");
189 if (nColon != string::npos)
190 {
191 string strHeader = str.substr(0, nColon);
192 boost::trim(strHeader);
193 boost::to_lower(strHeader);
194 string strValue = str.substr(nColon+1);
195 boost::trim(strValue);
196 mapHeadersRet[strHeader] = strValue;
197 if (strHeader == "content-length")
198 nLen = atoi(strValue.c_str());
199 }
200 }
201 return nLen;
202}
203
204
205int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
206 string>& mapHeadersRet, string& strMessageRet,
733177eb 207 int nProto, size_t max_size)
fb78cc23
WL
208{
209 mapHeadersRet.clear();
210 strMessageRet = "";
211
212 // Read header
213 int nLen = ReadHTTPHeaders(stream, mapHeadersRet);
733177eb 214 if (nLen < 0 || (size_t)nLen > max_size)
fb78cc23
WL
215 return HTTP_INTERNAL_SERVER_ERROR;
216
217 // Read message
218 if (nLen > 0)
219 {
2ec5a3d2
WL
220 vector<char> vch;
221 size_t ptr = 0;
222 while (ptr < (size_t)nLen)
223 {
224 size_t bytes_to_read = std::min((size_t)nLen - ptr, POST_READ_SIZE);
225 vch.resize(ptr + bytes_to_read);
226 stream.read(&vch[ptr], bytes_to_read);
227 if (!stream) // Connection lost while reading
228 return HTTP_INTERNAL_SERVER_ERROR;
229 ptr += bytes_to_read;
230 }
fb78cc23
WL
231 strMessageRet = string(vch.begin(), vch.end());
232 }
233
234 string sConHdr = mapHeadersRet["connection"];
235
236 if ((sConHdr != "close") && (sConHdr != "keep-alive"))
237 {
238 if (nProto >= 1)
239 mapHeadersRet["connection"] = "keep-alive";
240 else
241 mapHeadersRet["connection"] = "close";
242 }
243
244 return HTTP_OK;
245}
246
72fb3d29
MF
247/**
248 * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
249 * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
250 * unspecified (HTTP errors and contents of 'error').
251 *
252 * 1.0 spec: http://json-rpc.org/wiki/specification
253 * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
254 * http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
255 */
fb78cc23
WL
256
257string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
258{
259 Object request;
260 request.push_back(Pair("method", strMethod));
261 request.push_back(Pair("params", params));
262 request.push_back(Pair("id", id));
263 return write_string(Value(request), false) + "\n";
264}
265
266Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
267{
268 Object reply;
269 if (error.type() != null_type)
270 reply.push_back(Pair("result", Value::null));
271 else
272 reply.push_back(Pair("result", result));
273 reply.push_back(Pair("error", error));
274 reply.push_back(Pair("id", id));
275 return reply;
276}
277
278string JSONRPCReply(const Value& result, const Value& error, const Value& id)
279{
280 Object reply = JSONRPCReplyObj(result, error, id);
281 return write_string(Value(reply), false) + "\n";
282}
283
284Object JSONRPCError(int code, const string& message)
285{
286 Object error;
287 error.push_back(Pair("code", code));
288 error.push_back(Pair("message", message));
289 return error;
290}
This page took 0.216366 seconds and 4 git commands to generate.