mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
@@ -88,7 +88,7 @@ PROTO_SRCS = env.Protoc([], 'src/ripple.proto', PROTOCOUTDIR='obj', PROTOCPYTHON
|
||||
env.Clean(PROTO_SRCS, 'site_scons/site_tools/protoc.pyc')
|
||||
|
||||
# Remove unused source files.
|
||||
UNUSED_SRCS = ['src/HttpReply.cpp']
|
||||
UNUSED_SRCS = []
|
||||
|
||||
for file in UNUSED_SRCS:
|
||||
NEWCOIN_SRCS.remove(file)
|
||||
|
||||
15
js/amount.js
15
js/amount.js
@@ -258,6 +258,15 @@ Amount.prototype.canonicalize = function() {
|
||||
}
|
||||
};
|
||||
|
||||
Amount.prototype.negate = function () {
|
||||
if (this.is_native) {
|
||||
this.value.negate();
|
||||
}
|
||||
else {
|
||||
this.is_negative = !this.is_negative;
|
||||
}
|
||||
};
|
||||
|
||||
Amount.prototype.to_json = function() {
|
||||
if (this.is_native) {
|
||||
return this.to_text();
|
||||
@@ -400,6 +409,12 @@ Amount.prototype.parse_json = function(j) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Amount.prototype.parse_issuer = function (issuer) {
|
||||
this.issuer.parse_json(issuer);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
exports.setAccounts = setAccounts;
|
||||
exports.Amount = Amount;
|
||||
exports.Currency = Currency;
|
||||
|
||||
129
js/remote.js
129
js/remote.js
@@ -16,8 +16,8 @@ var EventEmitter = require('events').EventEmitter;
|
||||
// npm
|
||||
var WebSocket = require('ws');
|
||||
|
||||
var amount = require('./amount.js');
|
||||
var Amount = amount.Amount;
|
||||
var Amount = require('./amount.js').Amount;
|
||||
var UInt160 = require('./amount.js').UInt160;
|
||||
|
||||
// Request events emmitted:
|
||||
// 'success' : Request successful.
|
||||
@@ -63,10 +63,23 @@ Request.prototype.request_default = function () {
|
||||
this.remote.request(this);
|
||||
};
|
||||
|
||||
Request.prototype.ledger_choose = function (current) {
|
||||
if (current)
|
||||
{
|
||||
this.message.ledger_index = this.remote.ledger_current_index;
|
||||
}
|
||||
else {
|
||||
this.message.ledger = this.remote.ledger_closed;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Set the ledger for a request.
|
||||
// - ledger_entry
|
||||
Request.prototype.ledger = function (ledger) {
|
||||
this.message.ledger = ledger;
|
||||
// - transaction_entry
|
||||
Request.prototype.ledger_closed = function (ledger) {
|
||||
this.message.ledger_closed = ledger;
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -104,6 +117,15 @@ Request.prototype.transaction = function (t) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.ripple_state = function (account, issuer, currency) {
|
||||
this.message.ripple_state = {
|
||||
'accounts' : [ account, issuer ],
|
||||
'currency' : currency
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
//
|
||||
// Remote - access to a remote Ripple server via websocket.
|
||||
//
|
||||
@@ -463,9 +485,10 @@ Remote.prototype.request_ledger_entry = function (type) {
|
||||
// Transparent caching:
|
||||
request.on('request', function (remote) { // Intercept default request.
|
||||
if (this.ledger_closed) {
|
||||
// XXX Initial implementation no caching.
|
||||
// XXX Add caching.
|
||||
}
|
||||
// else if (req.ledger_index)
|
||||
// else if ('ripple_state' === this.type) // YYY Could be cached per ledger.
|
||||
else if ('account_root' === this.type) {
|
||||
var cache = self.ledgers.current.account_root;
|
||||
|
||||
@@ -507,17 +530,11 @@ Remote.prototype.request_ledger_entry = function (type) {
|
||||
return request;
|
||||
};
|
||||
|
||||
// --> ledger_closed : optional
|
||||
Remote.prototype.request_transaction_entry = function (hash, ledger_closed) {
|
||||
Remote.prototype.request_transaction_entry = function (hash) {
|
||||
assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol.
|
||||
|
||||
var request = new Request(this, 'transaction_entry');
|
||||
|
||||
request.message.transaction = hash;
|
||||
if (ledger_closed)
|
||||
request.message.ledger_closed = ledger_closed;
|
||||
|
||||
return request;
|
||||
return (new Request(this, 'transaction_entry'))
|
||||
.transaction(hash);
|
||||
};
|
||||
|
||||
// Submit a transaction.
|
||||
@@ -587,10 +604,8 @@ Remote.prototype.submit = function (transaction) {
|
||||
Remote.prototype._server_subscribe = function () {
|
||||
var self = this;
|
||||
|
||||
var request = new Request(this, 'server_subscribe');
|
||||
|
||||
request.
|
||||
on('success', function (message) {
|
||||
(new Request(this, 'server_subscribe'))
|
||||
.on('success', function (message) {
|
||||
self.stand_alone = !!message.stand_alone;
|
||||
|
||||
if (message.ledger_closed && message.ledger_current_index) {
|
||||
@@ -614,9 +629,8 @@ Remote.prototype._server_subscribe = function () {
|
||||
Remote.prototype.ledger_accept = function () {
|
||||
if (this.stand_alone || undefined === this.stand_alone)
|
||||
{
|
||||
var request = new Request(this, 'ledger_accept');
|
||||
|
||||
request.request();
|
||||
(new Request(this, 'ledger_accept'))
|
||||
.request();
|
||||
}
|
||||
else {
|
||||
this.emit('error', {
|
||||
@@ -627,6 +641,17 @@ Remote.prototype.ledger_accept = function () {
|
||||
return this;
|
||||
};
|
||||
|
||||
// Return a request to refresh the account balance.
|
||||
Remote.prototype.request_account_balance = function (account, current) {
|
||||
return (this.request_ledger_entry('account_root'))
|
||||
.account_root(account)
|
||||
.ledger_choose(current)
|
||||
.on('success', function (message) {
|
||||
// If the caller also waits for 'success', they might run before this.
|
||||
request.emit('account_balance', message.node.Balance);
|
||||
});
|
||||
};
|
||||
|
||||
// Return the next account sequence if possible.
|
||||
// <-- undefined or Sequence
|
||||
Remote.prototype.account_seq = function (account, advance) {
|
||||
@@ -648,29 +673,19 @@ Remote.prototype.account_seq_cache = function (account, current) {
|
||||
var self = this;
|
||||
var request = this.request_ledger_entry('account_root');
|
||||
|
||||
request
|
||||
return request
|
||||
.account_root(account)
|
||||
.ledger_choose(current)
|
||||
.on('success', function (message) {
|
||||
var seq = message.node.Sequence;
|
||||
|
||||
if (!self.accounts[account])
|
||||
self.accounts[account] = {};
|
||||
var seq = message.node.Sequence;
|
||||
|
||||
if (!self.accounts[account]) self.accounts[account] = {};
|
||||
|
||||
self.accounts[account].seq = seq;
|
||||
self.accounts[account].seq = seq;
|
||||
|
||||
// If the caller also waits for 'success', they might run before this.
|
||||
request.emit('success_account_seq_cache');
|
||||
});
|
||||
|
||||
if (current)
|
||||
{
|
||||
request.ledger_index(this.ledger_current_index);
|
||||
}
|
||||
else {
|
||||
request.ledger(this.ledger_closed);
|
||||
}
|
||||
|
||||
return request;
|
||||
// If the caller also waits for 'success', they might run before this.
|
||||
request.emit('success_account_seq_cache');
|
||||
});
|
||||
};
|
||||
|
||||
// Mark an account's root node as dirty.
|
||||
@@ -678,6 +693,37 @@ Remote.prototype.dirty_account_root = function (account) {
|
||||
delete this.ledgers.current.account_root[account];
|
||||
};
|
||||
|
||||
// Return a request to get a ripple balance.
|
||||
//
|
||||
// --> account: String
|
||||
// --> issuer: String
|
||||
// --> currency: String
|
||||
// --> current: bool : true = current ledger
|
||||
Remote.prototype.request_ripple_balance = function (account, issuer, currency, current) {
|
||||
var src = this.remote.config.accounts[account] ? this.remote.config.accounts[account].account : account;
|
||||
var dst = this.remote.config.accounts[issuer] ? this.remote.config.accounts[issuer].account : issuer;
|
||||
|
||||
return (this.request_ledger_entry('ripple_state')) // YYY Could be cached per ledger.
|
||||
.ripple_state(src, dst, currency)
|
||||
.ledger_choose(current)
|
||||
.on('success', function (message) {
|
||||
var node = message.node;
|
||||
var flip = UInt160.from_json(src) == node.HighLimit.issuer;
|
||||
var issuerLimit = flip ? node.LowLimit : node.HighLimit;
|
||||
var accountLimit = flip ? node.HighLimit : node.LowLimit;
|
||||
var issuerBalance = (flip ? node.Balance.clone().negate() : node.Balance.clone()).parse_issuer(dst);
|
||||
var accountBalance = issuerBalance.clone().parse_issuer(dst);
|
||||
|
||||
// If the caller also waits for 'success', they might run before this.
|
||||
request.emit('ripple_state', {
|
||||
'issuer_balance' : issuerBalance, // Balance with dst as issuer.
|
||||
'account_balance' : accountBalance, // Balance with src as issuer.
|
||||
'issuer_limit' : issuerLimit.clone().parse_issuer(src), // Limit set by issuer with src as issuer.
|
||||
'account_limit' : accountLimit.clone().parse_issuer(dst) // Limit set by account with dst as issuer.
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Remote.prototype.transaction = function () {
|
||||
return new Transaction(this);
|
||||
};
|
||||
@@ -849,7 +895,8 @@ Transaction.prototype.submit = function () {
|
||||
var stop = false;
|
||||
|
||||
// XXX make sure self.hash is available.
|
||||
self.remote.request_transaction_entry(self.hash, ledger_closed)
|
||||
self.remote.request_transaction_entry(self.hash)
|
||||
.ledger_closed(ledger_closed)
|
||||
.on('success', function (message) {
|
||||
self.set_state(message.metadata.TransactionResult);
|
||||
self.emit('final', message);
|
||||
|
||||
102
src/HTTPRequest.cpp
Normal file
102
src/HTTPRequest.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "HTTPRequest.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "Log.h"
|
||||
SETUP_LOG();
|
||||
|
||||
void HTTPRequest::reset()
|
||||
{
|
||||
vHeaders.clear();
|
||||
sRequestBody.clear();
|
||||
sAuthorization.clear();
|
||||
iDataSize = 0;
|
||||
bShouldClose = true;
|
||||
eState = await_request;
|
||||
}
|
||||
|
||||
HTTPRequestAction HTTPRequest::requestDone(bool forceClose)
|
||||
{
|
||||
if (forceClose || bShouldClose)
|
||||
return haCLOSE_CONN;
|
||||
reset();
|
||||
return haREAD_LINE;
|
||||
}
|
||||
|
||||
std::string HTTPRequest::getReplyHeaders(bool forceClose)
|
||||
{
|
||||
if (forceClose || bShouldClose)
|
||||
return "Connection: close\r\n";
|
||||
else
|
||||
return "Connection: Keep-Alive\r\n";
|
||||
}
|
||||
|
||||
HTTPRequestAction HTTPRequest::consume(boost::asio::streambuf& buf)
|
||||
{
|
||||
std::string line;
|
||||
std::istream is(&buf);
|
||||
std::getline(is, line);
|
||||
boost::trim(line);
|
||||
|
||||
// cLog(lsTRACE) << "HTTPRequest line: " << line;
|
||||
|
||||
if (eState == await_request)
|
||||
{ // VERB URL PROTO
|
||||
if (line.empty())
|
||||
return haREAD_LINE;
|
||||
sRequest = line;
|
||||
bShouldClose = sRequest.find("HTTP/1.1") == std::string::npos;
|
||||
|
||||
eState = await_header;
|
||||
return haREAD_LINE;
|
||||
}
|
||||
|
||||
if (eState == await_header)
|
||||
{ // HEADER_NAME: HEADER_BODY
|
||||
if (line.empty()) // empty line or bare \r
|
||||
{
|
||||
if (iDataSize == 0)
|
||||
{ // no body
|
||||
eState = do_request;
|
||||
return haDO_REQUEST;
|
||||
}
|
||||
eState = getting_body;
|
||||
return haREAD_RAW;
|
||||
}
|
||||
vHeaders.push_back(line);
|
||||
|
||||
size_t colon = line.find(':');
|
||||
if (colon != std::string::npos)
|
||||
{
|
||||
std::string headerName = line.substr(0, colon);
|
||||
boost::trim(headerName);
|
||||
boost::to_lower(headerName);
|
||||
|
||||
std::string headerValue = line.substr(colon+1);
|
||||
boost::trim(headerValue);
|
||||
|
||||
if (headerName == "connection")
|
||||
{
|
||||
boost::to_lower(headerValue);
|
||||
if ((headerValue == "keep-alive") || (headerValue == "keepalive"))
|
||||
bShouldClose = false;
|
||||
if (headerValue == "close")
|
||||
bShouldClose = true;
|
||||
}
|
||||
|
||||
if (headerName == "content-length")
|
||||
iDataSize = boost::lexical_cast<int>(headerValue);
|
||||
|
||||
if (headerName == "authorization")
|
||||
sAuthorization = headerValue;
|
||||
|
||||
}
|
||||
|
||||
return haREAD_LINE;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return haERROR;
|
||||
}
|
||||
61
src/HTTPRequest.h
Normal file
61
src/HTTPRequest.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef HTTPREQUEST__HPP
|
||||
#define HTTPREQUEST__HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
|
||||
enum HTTPRequestAction
|
||||
{ // What the application code needs to do
|
||||
haERROR = 0,
|
||||
haREAD_LINE = 1,
|
||||
haREAD_RAW = 2,
|
||||
haDO_REQUEST = 3,
|
||||
haCLOSE_CONN = 4
|
||||
};
|
||||
|
||||
class HTTPRequest
|
||||
{ // an HTTP request in progress
|
||||
protected:
|
||||
|
||||
enum state
|
||||
{
|
||||
await_request, // We are waiting for the request line
|
||||
await_header, // We are waiting for request headers
|
||||
getting_body, // We are waiting for the body
|
||||
do_request, // We are waiting for the request to complete
|
||||
};
|
||||
|
||||
state eState;
|
||||
std::string sRequest; // VERB URL PROTO
|
||||
std::string sRequestBody;
|
||||
std::string sAuthorization;
|
||||
|
||||
std::vector<std::string> vHeaders;
|
||||
|
||||
int iDataSize;
|
||||
bool bShouldClose;
|
||||
|
||||
public:
|
||||
|
||||
HTTPRequest() : eState(await_request), iDataSize(0), bShouldClose(true) { ; }
|
||||
void reset();
|
||||
|
||||
std::string& peekBody() { return sRequestBody; }
|
||||
std::string getBody() { return sRequestBody; }
|
||||
std::string& peekRequest() { return sRequest; }
|
||||
std::string getRequest() { return sRequest; }
|
||||
std::string& peekAuth() { return sAuthorization; }
|
||||
std::string getAuth() { return sAuthorization; }
|
||||
|
||||
std::vector<std::string>& peekHeaders() { return vHeaders; }
|
||||
std::string getReplyHeaders(bool forceClose);
|
||||
|
||||
HTTPRequestAction consume(boost::asio::streambuf&);
|
||||
HTTPRequestAction requestDone(bool forceClose); // call after reply is sent
|
||||
|
||||
int getDataSize() { return iDataSize; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,241 +0,0 @@
|
||||
#include "HttpReply.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
|
||||
namespace status_strings
|
||||
{
|
||||
const std::string ok =
|
||||
"HTTP/1.0 200 OK\r\n";
|
||||
const std::string created =
|
||||
"HTTP/1.0 201 Created\r\n";
|
||||
const std::string accepted =
|
||||
"HTTP/1.0 202 Accepted\r\n";
|
||||
const std::string no_content =
|
||||
"HTTP/1.0 204 No Content\r\n";
|
||||
const std::string multiple_choices =
|
||||
"HTTP/1.0 300 Multiple Choices\r\n";
|
||||
const std::string moved_permanently =
|
||||
"HTTP/1.0 301 Moved Permanently\r\n";
|
||||
const std::string moved_temporarily =
|
||||
"HTTP/1.0 302 Moved Temporarily\r\n";
|
||||
const std::string not_modified =
|
||||
"HTTP/1.0 304 Not Modified\r\n";
|
||||
const std::string bad_request =
|
||||
"HTTP/1.0 400 Bad Request\r\n";
|
||||
const std::string unauthorized =
|
||||
"HTTP/1.0 401 Unauthorized\r\n";
|
||||
const std::string forbidden =
|
||||
"HTTP/1.0 403 Forbidden\r\n";
|
||||
const std::string not_found =
|
||||
"HTTP/1.0 404 Not Found\r\n";
|
||||
const std::string internal_server_error =
|
||||
"HTTP/1.0 500 Internal Server Error\r\n";
|
||||
const std::string not_implemented =
|
||||
"HTTP/1.0 501 Not Implemented\r\n";
|
||||
const std::string bad_gateway =
|
||||
"HTTP/1.0 502 Bad Gateway\r\n";
|
||||
const std::string service_unavailable =
|
||||
"HTTP/1.0 503 Service Unavailable\r\n";
|
||||
|
||||
boost::asio::const_buffer to_buffer(HttpReply::status_type status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case HttpReply::ok:
|
||||
return boost::asio::buffer(ok);
|
||||
case HttpReply::created:
|
||||
return boost::asio::buffer(created);
|
||||
case HttpReply::accepted:
|
||||
return boost::asio::buffer(accepted);
|
||||
case HttpReply::no_content:
|
||||
return boost::asio::buffer(no_content);
|
||||
case HttpReply::multiple_choices:
|
||||
return boost::asio::buffer(multiple_choices);
|
||||
case HttpReply::moved_permanently:
|
||||
return boost::asio::buffer(moved_permanently);
|
||||
case HttpReply::moved_temporarily:
|
||||
return boost::asio::buffer(moved_temporarily);
|
||||
case HttpReply::not_modified:
|
||||
return boost::asio::buffer(not_modified);
|
||||
case HttpReply::bad_request:
|
||||
return boost::asio::buffer(bad_request);
|
||||
case HttpReply::unauthorized:
|
||||
return boost::asio::buffer(unauthorized);
|
||||
case HttpReply::forbidden:
|
||||
return boost::asio::buffer(forbidden);
|
||||
case HttpReply::not_found:
|
||||
return boost::asio::buffer(not_found);
|
||||
case HttpReply::internal_server_error:
|
||||
return boost::asio::buffer(internal_server_error);
|
||||
case HttpReply::not_implemented:
|
||||
return boost::asio::buffer(not_implemented);
|
||||
case HttpReply::bad_gateway:
|
||||
return boost::asio::buffer(bad_gateway);
|
||||
case HttpReply::service_unavailable:
|
||||
return boost::asio::buffer(service_unavailable);
|
||||
default:
|
||||
return boost::asio::buffer(internal_server_error);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace status_strings
|
||||
|
||||
namespace misc_strings
|
||||
{
|
||||
const char name_value_separator[] = { ':', ' ' };
|
||||
const char crlf[] = { '\r', '\n' };
|
||||
} // namespace misc_strings
|
||||
|
||||
std::vector<boost::asio::const_buffer> HttpReply::to_buffers()
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(status_strings::to_buffer(status));
|
||||
for (std::size_t i = 0; i < headers.size(); ++i)
|
||||
{
|
||||
HttpHeader& h = headers[i];
|
||||
buffers.push_back(boost::asio::buffer(h.name));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator));
|
||||
buffers.push_back(boost::asio::buffer(h.value));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
buffers.push_back(boost::asio::buffer(content));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
namespace stock_replies {
|
||||
|
||||
const char ok[] = "";
|
||||
const char created[] =
|
||||
"<html>"
|
||||
"<head><title>Created</title></head>"
|
||||
"<body><h1>201 Created</h1></body>"
|
||||
"</html>";
|
||||
const char accepted[] =
|
||||
"<html>"
|
||||
"<head><title>Accepted</title></head>"
|
||||
"<body><h1>202 Accepted</h1></body>"
|
||||
"</html>";
|
||||
const char no_content[] =
|
||||
"<html>"
|
||||
"<head><title>No Content</title></head>"
|
||||
"<body><h1>204 Content</h1></body>"
|
||||
"</html>";
|
||||
const char multiple_choices[] =
|
||||
"<html>"
|
||||
"<head><title>Multiple Choices</title></head>"
|
||||
"<body><h1>300 Multiple Choices</h1></body>"
|
||||
"</html>";
|
||||
const char moved_permanently[] =
|
||||
"<html>"
|
||||
"<head><title>Moved Permanently</title></head>"
|
||||
"<body><h1>301 Moved Permanently</h1></body>"
|
||||
"</html>";
|
||||
const char moved_temporarily[] =
|
||||
"<html>"
|
||||
"<head><title>Moved Temporarily</title></head>"
|
||||
"<body><h1>302 Moved Temporarily</h1></body>"
|
||||
"</html>";
|
||||
const char not_modified[] =
|
||||
"<html>"
|
||||
"<head><title>Not Modified</title></head>"
|
||||
"<body><h1>304 Not Modified</h1></body>"
|
||||
"</html>";
|
||||
const char bad_request[] =
|
||||
"<html>"
|
||||
"<head><title>Bad Request</title></head>"
|
||||
"<body><h1>400 Bad Request</h1></body>"
|
||||
"</html>";
|
||||
const char unauthorized[] =
|
||||
"<html>"
|
||||
"<head><title>Unauthorized</title></head>"
|
||||
"<body><h1>401 Unauthorized</h1></body>"
|
||||
"</html>";
|
||||
const char forbidden[] =
|
||||
"<html>"
|
||||
"<head><title>Forbidden</title></head>"
|
||||
"<body><h1>403 Forbidden</h1></body>"
|
||||
"</html>";
|
||||
const char not_found[] =
|
||||
"<html>"
|
||||
"<head><title>Not Found</title></head>"
|
||||
"<body><h1>404 Not Found</h1></body>"
|
||||
"</html>";
|
||||
const char internal_server_error[] =
|
||||
"<html>"
|
||||
"<head><title>Internal Server Error</title></head>"
|
||||
"<body><h1>500 Internal Server Error</h1></body>"
|
||||
"</html>";
|
||||
const char not_implemented[] =
|
||||
"<html>"
|
||||
"<head><title>Not Implemented</title></head>"
|
||||
"<body><h1>501 Not Implemented</h1></body>"
|
||||
"</html>";
|
||||
const char bad_gateway[] =
|
||||
"<html>"
|
||||
"<head><title>Bad Gateway</title></head>"
|
||||
"<body><h1>502 Bad Gateway</h1></body>"
|
||||
"</html>";
|
||||
const char service_unavailable[] =
|
||||
"<html>"
|
||||
"<head><title>Service Unavailable</title></head>"
|
||||
"<body><h1>503 Service Unavailable</h1></body>"
|
||||
"</html>";
|
||||
|
||||
std::string to_string(HttpReply::status_type status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case HttpReply::ok:
|
||||
return ok;
|
||||
case HttpReply::created:
|
||||
return created;
|
||||
case HttpReply::accepted:
|
||||
return accepted;
|
||||
case HttpReply::no_content:
|
||||
return no_content;
|
||||
case HttpReply::multiple_choices:
|
||||
return multiple_choices;
|
||||
case HttpReply::moved_permanently:
|
||||
return moved_permanently;
|
||||
case HttpReply::moved_temporarily:
|
||||
return moved_temporarily;
|
||||
case HttpReply::not_modified:
|
||||
return not_modified;
|
||||
case HttpReply::bad_request:
|
||||
return bad_request;
|
||||
case HttpReply::unauthorized:
|
||||
return unauthorized;
|
||||
case HttpReply::forbidden:
|
||||
return forbidden;
|
||||
case HttpReply::not_found:
|
||||
return not_found;
|
||||
case HttpReply::internal_server_error:
|
||||
return internal_server_error;
|
||||
case HttpReply::not_implemented:
|
||||
return not_implemented;
|
||||
case HttpReply::bad_gateway:
|
||||
return bad_gateway;
|
||||
case HttpReply::service_unavailable:
|
||||
return service_unavailable;
|
||||
default:
|
||||
return internal_server_error;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace stock_replies
|
||||
|
||||
HttpReply HttpReply::stock_reply(HttpReply::status_type status)
|
||||
{
|
||||
HttpReply rep;
|
||||
rep.status = status;
|
||||
rep.content = stock_replies::to_string(status);
|
||||
rep.headers.resize(2);
|
||||
rep.headers[0].name = "Content-Length";
|
||||
rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size());
|
||||
rep.headers[1].name = "Content-Type";
|
||||
rep.headers[1].value = "text/html";
|
||||
return rep;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef HTTP_REPLY_HPP
|
||||
#define HTTP_REPLY_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/asio.hpp>
|
||||
#include "HttpRequest.h"
|
||||
|
||||
/// A reply to be sent to a client.
|
||||
class HttpReply
|
||||
{
|
||||
public:
|
||||
/// The status of the reply.
|
||||
enum status_type
|
||||
{
|
||||
ok = 200,
|
||||
created = 201,
|
||||
accepted = 202,
|
||||
no_content = 204,
|
||||
multiple_choices = 300,
|
||||
moved_permanently = 301,
|
||||
moved_temporarily = 302,
|
||||
not_modified = 304,
|
||||
bad_request = 400,
|
||||
unauthorized = 401,
|
||||
forbidden = 403,
|
||||
not_found = 404,
|
||||
internal_server_error = 500,
|
||||
not_implemented = 501,
|
||||
bad_gateway = 502,
|
||||
service_unavailable = 503
|
||||
} status;
|
||||
|
||||
/// The headers to be included in the reply.
|
||||
std::vector<HttpHeader> headers;
|
||||
|
||||
/// The content to be sent in the reply.
|
||||
std::string content;
|
||||
|
||||
/// Convert the reply into a vector of buffers. The buffers do not own the
|
||||
/// underlying memory blocks, therefore the reply object must remain valid and
|
||||
/// not be changed until the write operation has completed.
|
||||
std::vector<boost::asio::const_buffer> to_buffers();
|
||||
|
||||
/// Get a stock reply.
|
||||
static HttpReply stock_reply(status_type status);
|
||||
};
|
||||
|
||||
|
||||
#endif // HTTP_REPLY_HPP
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef HTTP_REQUEST_HPP
|
||||
#define HTTP_REQUEST_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct HttpHeader
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
/// A request received from a client.
|
||||
struct HttpRequest
|
||||
{
|
||||
std::string method;
|
||||
std::string uri;
|
||||
int http_version_major;
|
||||
int http_version_minor;
|
||||
std::vector<HttpHeader> headers;
|
||||
std::string mBody;
|
||||
};
|
||||
|
||||
#endif // HTTP_REQUEST_HPP
|
||||
@@ -1,7 +1,5 @@
|
||||
|
||||
#include "RPCServer.h"
|
||||
#include "RequestParser.h"
|
||||
#include "HttpReply.h"
|
||||
#include "HttpsClient.h"
|
||||
#include "Application.h"
|
||||
#include "RPC.h"
|
||||
@@ -22,6 +20,7 @@
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/asio/read_until.hpp>
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
@@ -30,6 +29,10 @@
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
#ifndef RPC_MAXIMUM_QUERY
|
||||
#define RPC_MAXIMUM_QUERY (1024*1024)
|
||||
#endif
|
||||
|
||||
RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwork)
|
||||
: mNetOps(nopNetwork), mSocket(io_service)
|
||||
{
|
||||
@@ -107,45 +110,79 @@ Json::Value RPCServer::RPCError(int iError)
|
||||
void RPCServer::connected()
|
||||
{
|
||||
//std::cout << "RPC request" << std::endl;
|
||||
if (mSocket.remote_endpoint().address().to_string()=="127.0.0.1") mRole=ADMIN;
|
||||
else mRole=GUEST;
|
||||
if (mSocket.remote_endpoint().address().to_string()=="127.0.0.1") mRole = ADMIN;
|
||||
else mRole = GUEST;
|
||||
|
||||
mSocket.async_read_some(boost::asio::buffer(mReadBuffer),
|
||||
boost::bind(&RPCServer::Shandle_read, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n",
|
||||
boost::bind(&RPCServer::handle_read_line, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void RPCServer::handle_read(const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred)
|
||||
void RPCServer::handle_read_req(const boost::system::error_code& e)
|
||||
{
|
||||
if (!e)
|
||||
std::string req;
|
||||
|
||||
if (mLineBuffer.size())
|
||||
{
|
||||
boost::tribool result;
|
||||
result = mRequestParser.parse(
|
||||
mIncomingRequest, mReadBuffer.data(), mReadBuffer.data() + bytes_transferred);
|
||||
req.assign(boost::asio::buffer_cast<const char*>(mLineBuffer.data()), mLineBuffer.size());
|
||||
mLineBuffer.consume(mLineBuffer.size());
|
||||
}
|
||||
|
||||
if (result)
|
||||
req += strCopy(mQueryVec);
|
||||
mReplyStr = handleRequest(req);
|
||||
boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr),
|
||||
boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void RPCServer::handle_read_line(const boost::system::error_code& e)
|
||||
{
|
||||
if (e)
|
||||
return;
|
||||
|
||||
HTTPRequestAction action = mHTTPRequest.consume(mLineBuffer);
|
||||
|
||||
if (action == haDO_REQUEST)
|
||||
{ // request with no body
|
||||
cLog(lsWARNING) << "RPC HTTP request with no body";
|
||||
boost::system::error_code ignore_ec;
|
||||
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_ec);
|
||||
return;
|
||||
}
|
||||
else if (action == haREAD_LINE)
|
||||
{
|
||||
boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n",
|
||||
boost::bind(&RPCServer::handle_read_line, shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
else if (action == haREAD_RAW)
|
||||
{
|
||||
int rLen = mHTTPRequest.getDataSize();
|
||||
if ((rLen < 0) || (rLen > RPC_MAXIMUM_QUERY))
|
||||
{
|
||||
mReplyStr = handleRequest(mIncomingRequest.mBody);
|
||||
|
||||
sendReply();
|
||||
cLog(lsWARNING) << "Illegal RPC request length " << rLen;
|
||||
boost::system::error_code ignore_ec;
|
||||
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_ec);
|
||||
return;
|
||||
}
|
||||
else if (!result)
|
||||
{ // bad request
|
||||
std::cout << "bad request: " << mIncomingRequest.mBody <<std::endl;
|
||||
|
||||
int alreadyHave = mLineBuffer.size();
|
||||
|
||||
if (alreadyHave < rLen)
|
||||
{
|
||||
mQueryVec.resize(rLen - alreadyHave);
|
||||
boost::asio::async_read(mSocket, boost::asio::buffer(mQueryVec),
|
||||
boost::bind(&RPCServer::handle_read_req, shared_from_this(), boost::asio::placeholders::error));
|
||||
cLog(lsTRACE) << "Waiting for completed request: " << rLen;
|
||||
}
|
||||
else
|
||||
{ // not done keep reading
|
||||
mSocket.async_read_some(boost::asio::buffer(mReadBuffer),
|
||||
boost::bind(&RPCServer::Shandle_read, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
{ // we have the whole thing
|
||||
mQueryVec.resize(0);
|
||||
handle_read_req(e);
|
||||
}
|
||||
}
|
||||
else if (e != boost::asio::error::operation_aborted)
|
||||
else
|
||||
{
|
||||
|
||||
boost::system::error_code ignore_ec;
|
||||
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_ec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2769,48 +2806,23 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
|
||||
}
|
||||
}
|
||||
|
||||
void RPCServer::sendReply()
|
||||
{
|
||||
//std::cout << "RPC reply: " << mReplyStr << std::endl;
|
||||
boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr),
|
||||
boost::bind(&RPCServer::Shandle_write, shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void RPCServer::handle_write(const boost::system::error_code& e)
|
||||
{
|
||||
//std::cout << "async_write complete " << e << std::endl;
|
||||
|
||||
if (!e)
|
||||
{
|
||||
bool keep_alive = (mIncomingRequest.http_version_major == 1) && (mIncomingRequest.http_version_minor >= 1);
|
||||
BOOST_FOREACH(HttpHeader& h, mIncomingRequest.headers)
|
||||
{
|
||||
if (boost::iequals(h.name, "connection"))
|
||||
{
|
||||
if (boost::iequals(h.value, "keep-alive"))
|
||||
keep_alive = true;
|
||||
if (boost::iequals(h.value, "close"))
|
||||
keep_alive = false;
|
||||
}
|
||||
}
|
||||
if (keep_alive)
|
||||
{
|
||||
mIncomingRequest.method.clear();
|
||||
mIncomingRequest.uri.clear();
|
||||
mIncomingRequest.mBody.clear();
|
||||
mIncomingRequest.headers.clear();
|
||||
mRequestParser.reset();
|
||||
mSocket.async_read_some(boost::asio::buffer(mReadBuffer),
|
||||
boost::bind(&RPCServer::Shandle_read, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
else
|
||||
HTTPRequestAction action = mHTTPRequest.requestDone(false);
|
||||
if (action == haCLOSE_CONN)
|
||||
{
|
||||
boost::system::error_code ignored_ec;
|
||||
mSocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::async_read_until(mSocket, mLineBuffer, "\r\n",
|
||||
boost::bind(&RPCServer::handle_read_line, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
if (e != boost::asio::error::operation_aborted)
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
#include "../json/value.h"
|
||||
|
||||
#include "HttpRequest.h"
|
||||
#include "RequestParser.h"
|
||||
#include "HTTPRequest.h"
|
||||
#include "NewcoinAddress.h"
|
||||
#include "NetworkOPs.h"
|
||||
#include "SerializedLedger.h"
|
||||
@@ -91,11 +90,12 @@ private:
|
||||
NetworkOPs* mNetOps;
|
||||
|
||||
boost::asio::ip::tcp::socket mSocket;
|
||||
boost::array<char, 8192> mReadBuffer;
|
||||
|
||||
boost::asio::streambuf mLineBuffer;
|
||||
std::vector<unsigned char> mQueryVec;
|
||||
std::string mReplyStr;
|
||||
|
||||
HttpRequest mIncomingRequest;
|
||||
HttpRequestParser mRequestParser;
|
||||
HTTPRequest mHTTPRequest;
|
||||
|
||||
enum { GUEST, USER, ADMIN };
|
||||
int mRole;
|
||||
@@ -106,15 +106,10 @@ private:
|
||||
RPCServer& operator=(const RPCServer&); // no implementation
|
||||
|
||||
void handle_write(const boost::system::error_code& ec);
|
||||
static void Shandle_write(pointer This, const boost::system::error_code& ec)
|
||||
{ This->handle_write(ec); }
|
||||
|
||||
void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
|
||||
static void Shandle_read(pointer This, const boost::system::error_code& ec, std::size_t bytes_transferred)
|
||||
{ This->handle_read(ec, bytes_transferred); }
|
||||
void handle_read_line(const boost::system::error_code& ec);
|
||||
void handle_read_req(const boost::system::error_code& ec);
|
||||
|
||||
std::string handleRequest(const std::string& requestStr);
|
||||
void sendReply();
|
||||
|
||||
Json::Value doCommand(const std::string& command, Json::Value& params);
|
||||
int getParamCount(const Json::Value& params);
|
||||
|
||||
@@ -1,330 +0,0 @@
|
||||
#include "RequestParser.h"
|
||||
#include "HttpRequest.h"
|
||||
|
||||
|
||||
|
||||
HttpRequestParser::HttpRequestParser()
|
||||
: state_(method_start)
|
||||
{
|
||||
}
|
||||
|
||||
void HttpRequestParser::reset()
|
||||
{
|
||||
state_ = method_start;
|
||||
}
|
||||
|
||||
//template <typename InputIterator>
|
||||
boost::tribool HttpRequestParser::parse(HttpRequest& req,
|
||||
char* begin, char* end)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
boost::tribool result = consume(req, *begin++);
|
||||
if (result || !result)
|
||||
{
|
||||
std::string temp(begin,end);
|
||||
req.mBody=temp;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
boost::tribool result = boost::indeterminate;
|
||||
return result;
|
||||
}
|
||||
|
||||
boost::tribool HttpRequestParser::consume(HttpRequest& req, char input)
|
||||
{
|
||||
switch (state_)
|
||||
{
|
||||
case method_start:
|
||||
if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = method;
|
||||
req.method.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case method:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = uri;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.method.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri_start:
|
||||
if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = uri;
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = http_version_h;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case http_version_h:
|
||||
if (input == 'H')
|
||||
{
|
||||
state_ = http_version_t_1;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_t_1:
|
||||
if (input == 'T')
|
||||
{
|
||||
state_ = http_version_t_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_t_2:
|
||||
if (input == 'T')
|
||||
{
|
||||
state_ = http_version_p;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_p:
|
||||
if (input == 'P')
|
||||
{
|
||||
state_ = http_version_slash;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_slash:
|
||||
if (input == '/')
|
||||
{
|
||||
req.http_version_major = 0;
|
||||
req.http_version_minor = 0;
|
||||
state_ = http_version_major_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_major_start:
|
||||
if (is_digit(input))
|
||||
{
|
||||
req.http_version_major = req.http_version_major * 10 + input - '0';
|
||||
state_ = http_version_major;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_major:
|
||||
if (input == '.')
|
||||
{
|
||||
state_ = http_version_minor_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_digit(input))
|
||||
{
|
||||
req.http_version_major = req.http_version_major * 10 + input - '0';
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_minor_start:
|
||||
if (is_digit(input))
|
||||
{
|
||||
req.http_version_minor = req.http_version_minor * 10 + input - '0';
|
||||
state_ = http_version_minor;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_minor:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_1;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_digit(input))
|
||||
{
|
||||
req.http_version_minor = req.http_version_minor * 10 + input - '0';
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_1:
|
||||
if (input == '\n')
|
||||
{
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case header_line_start:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_3;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (!req.headers.empty() && (input == ' ' || input == '\t'))
|
||||
{
|
||||
state_ = header_lws;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.headers.push_back(HttpHeader());
|
||||
req.headers.back().name.push_back(input);
|
||||
state_ = header_name;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_lws:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (input == ' ' || input == '\t')
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = header_value;
|
||||
req.headers.back().value.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_name:
|
||||
if (input == ':')
|
||||
{
|
||||
state_ = space_before_header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.headers.back().name.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case space_before_header_value:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case header_value:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.headers.back().value.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case expecting_newline_2:
|
||||
if (input == '\n')
|
||||
{
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_3:
|
||||
return (input == '\n');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HttpRequestParser::is_char(int c)
|
||||
{
|
||||
return c >= 0 && c <= 127;
|
||||
}
|
||||
|
||||
bool HttpRequestParser::is_ctl(int c)
|
||||
{
|
||||
return (c >= 0 && c <= 31) || (c == 127);
|
||||
}
|
||||
|
||||
bool HttpRequestParser::is_tspecial(int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '(': case ')': case '<': case '>': case '@':
|
||||
case ',': case ';': case ':': case '\\': case '"':
|
||||
case '/': case '[': case ']': case '?': case '=':
|
||||
case '{': case '}': case ' ': case '\t':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HttpRequestParser::is_digit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#ifndef HTTP_REQUEST_PARSER_HPP
|
||||
#define HTTP_REQUEST_PARSER_HPP
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
|
||||
|
||||
struct HttpRequest;
|
||||
|
||||
/// Parser for incoming requests.
|
||||
class HttpRequestParser
|
||||
{
|
||||
/// Handle the next character of input.
|
||||
boost::tribool consume(HttpRequest& req, char input);
|
||||
|
||||
/// Check if a byte is an HTTP character.
|
||||
static bool is_char(int c);
|
||||
|
||||
/// Check if a byte is an HTTP control character.
|
||||
static bool is_ctl(int c);
|
||||
|
||||
/// Check if a byte is defined as an HTTP special character.
|
||||
static bool is_tspecial(int c);
|
||||
|
||||
/// Check if a byte is a digit.
|
||||
static bool is_digit(int c);
|
||||
|
||||
/// The current state of the parser.
|
||||
enum state
|
||||
{
|
||||
method_start,
|
||||
method,
|
||||
uri_start,
|
||||
uri,
|
||||
http_version_h,
|
||||
http_version_t_1,
|
||||
http_version_t_2,
|
||||
http_version_p,
|
||||
http_version_slash,
|
||||
http_version_major_start,
|
||||
http_version_major,
|
||||
http_version_minor_start,
|
||||
http_version_minor,
|
||||
expecting_newline_1,
|
||||
header_line_start,
|
||||
header_lws,
|
||||
header_name,
|
||||
space_before_header_value,
|
||||
header_value,
|
||||
expecting_newline_2,
|
||||
expecting_newline_3
|
||||
} state_;
|
||||
public:
|
||||
/// Construct ready to parse the request method.
|
||||
HttpRequestParser();
|
||||
|
||||
/// Reset to initial parser state.
|
||||
void reset();
|
||||
|
||||
/// Parse some data. The tribool return value is true when a complete request
|
||||
/// has been parsed, false if the data is invalid, indeterminate when more
|
||||
/// data is required. The InputIterator return value indicates how much of the
|
||||
/// input has been consumed.
|
||||
//template <typename InputIterator>
|
||||
boost::tribool parse(HttpRequest& req, char*, char*);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // HTTP_REQUEST_PARSER_HPP
|
||||
@@ -577,7 +577,7 @@ void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvR
|
||||
void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest)
|
||||
{
|
||||
NetworkOPs& noNetwork = mNetwork;
|
||||
uint256 uLedger = jvRequest.isMember("ledger") ? uint256(jvRequest["ledger"].asString()) : 0;
|
||||
uint256 uLedger = jvRequest.isMember("ledger_closed") ? uint256(jvRequest["ledger_closed"].asString()) : 0;
|
||||
uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0;
|
||||
|
||||
Ledger::pointer lpLedger;
|
||||
|
||||
@@ -80,7 +80,7 @@ buster.testCase("Remote functions", {
|
||||
|
||||
alpha
|
||||
.request_ledger_entry('account_root')
|
||||
.ledger(r.ledger_closed)
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.account_root("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
|
||||
.on('success', function (r) {
|
||||
// console.log("account_root: %s", JSON.stringify(r));
|
||||
@@ -110,7 +110,7 @@ buster.testCase("Remote functions", {
|
||||
|
||||
alpha
|
||||
.request_ledger_entry('account_root')
|
||||
.ledger(r.ledger_closed)
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.account_root("zHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
|
||||
.on('success', function (r) {
|
||||
// console.log("account_root: %s", JSON.stringify(r));
|
||||
@@ -141,7 +141,7 @@ buster.testCase("Remote functions", {
|
||||
|
||||
alpha
|
||||
.request_ledger_entry('account_root')
|
||||
.ledger(r.ledger_closed)
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.account_root(config.accounts.alice.account)
|
||||
.on('success', function (r) {
|
||||
// console.log("account_root: %s", JSON.stringify(r));
|
||||
@@ -171,7 +171,7 @@ buster.testCase("Remote functions", {
|
||||
|
||||
alpha
|
||||
.request_ledger_entry('index')
|
||||
.ledger(r.ledger_closed)
|
||||
.ledger_closed(r.ledger_closed)
|
||||
.account_root(config.accounts.alice.account)
|
||||
.index("2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8")
|
||||
.on('success', function (r) {
|
||||
|
||||
Reference in New Issue
Block a user