- client: generalize the GUI RPC mechanism to access via HTTP.

The handler checks for POST headers,
		and if present adds a reply header.
		Also: remove the restriction that request messages
		must be read in their entirety on the first recv().

		I'm testing this using javascript's XMLHttpRequest.
		It's not completely working;
		the browser sends an OPTIONS request, then sends a POST.
		The BOINC client parses and replies to these,
		but for some reason the browser doesn't seem to be
		parsing the POST reply.

svn path=/trunk/boinc/; revision=20774
This commit is contained in:
David Anderson 2010-03-02 22:52:22 +00:00
parent fe67e7c4e9
commit 87a8fb1aee
4 changed files with 91 additions and 10 deletions

View File

@ -1535,3 +1535,21 @@ David 2 Mar 2010
- add remote job submission system (from Toni Giorgino)
rboinc/*
David 2 Mar 2010
- client: generalize the GUI RPC mechanism to access via HTTP.
The handler checks for POST headers,
and if present adds a reply header.
Also: remove the restriction that request messages
must be read in their entirety on the first recv().
I'm testing this using javascript's XMLHttpRequest.
It's not completely working;
the browser sends an OPTIONS request, then sends a POST.
The BOINC client parses and replies to these,
but for some reason the browser doesn't seem to be
parsing the POST reply.
client/
gui_rpc_server.cpp,h
gui_rpc_server_ops.cpp

View File

@ -80,6 +80,7 @@ GUI_RPC_CONN::GUI_RPC_CONN(int s):
got_auth2 = false;
sent_unauthorized = false;
notice_refresh = false;
request_nbytes = 0;
}
GUI_RPC_CONN::~GUI_RPC_CONN() {

View File

@ -33,10 +33,13 @@
#define AU_MGR_GOT 1
#define AU_MGR_QUIT_REQ 2
#define AU_MGR_QUIT_SENT 3
#define GUI_RPC_REQ_MSG_SIZE 4096
class GUI_RPC_CONN {
public:
int sock;
char request_msg[GUI_RPC_REQ_MSG_SIZE+1];
int request_nbytes;
char nonce[256];
/// if true, don't allow operations other than authentication
bool auth_needed;

View File

@ -1067,30 +1067,84 @@ static void handle_get_notices_public(char* buf, MIOFILE& fout, bool notice_refr
notices.write(seqno, fout, true, notice_refresh);
}
static bool complete_post_request(char* buf) {
if (strncmp(buf, "POST", 4)) return false;
char* p = strstr(buf, "Content-Length: ");
if (!p) return false;
p += strlen("Content-Length: ");
int n = atoi(p);
p = strstr(p, "\r\n\r\n");
if (!p) return false;
p += 4;
if ((int)strlen(p) < n) return false;
return true;
}
// Some of the RPCs have empty-element request messages.
// We accept both <foo/> and <foo></foo>
//
#define match_req(buf, tag) (match_tag(buf, "<" tag ">") || match_tag(buf, "<" tag "/>"))
int GUI_RPC_CONN::handle_rpc() {
char request_msg[4096];
int n, retval=0;
MIOFILE mf;
MFILE m;
char* p;
mf.init_mfile(&m);
// read the request message in one read()
// so that the core client won't hang because
// of malformed request msgs
//
int left = GUI_RPC_REQ_MSG_SIZE - request_nbytes;
#ifdef _WIN32
n = recv(sock, request_msg, 4095, 0);
n = recv(sock, request_msg+request_nbytes, left, 0);
#else
n = read(sock, request_msg, 4095);
n = read(sock, request_msg+request_nbytes, left);
#endif
if (n <= 0) return ERR_READ;
request_msg[n-1] = 0; // replace 003 with NULL
if (n <= 0) {
request_nbytes = 0;
return ERR_READ;
}
request_nbytes += n;
// buffer full?
if (request_nbytes >= GUI_RPC_REQ_MSG_SIZE) {
request_nbytes = 0;
return ERR_READ;
}
request_msg[request_nbytes] = 0;
if (!strncmp(request_msg, "OPTIONS", 7)) {
char buf[1024];
sprintf(buf, "HTTP/1.1 200 OK\n"
"Server: BOINC client\n"
"Access-Control-Allow-Origin: *\n"
"Access-Control-Allow-Methods: POST, GET, OPTIONS\n"
"Content-Length: 0\n"
"Keep-Alive: timeout=2, max=100\n"
"Connection: Keep-Alive\n"
"Content-Type: text/plain\n\n"
);
send(sock, buf, strlen(buf), 0);
request_nbytes = 0;
if (log_flags.guirpc_debug) {
msg_printf(0, MSG_INFO,
"[guirpc_debug] processed OPTIONS"
);
}
return 0;
}
bool http_request;
if (complete_post_request(request_msg)) {
http_request = true;
} else if (p = strchr(request_msg, 3)) {
*p = 0;
http_request = false;
} else {
if (log_flags.guirpc_debug) {
msg_printf(0, MSG_INFO,
"[guirpc_debug] partial GUI RPC Command = '%s'\n", request_msg
);
}
return 0;
}
request_nbytes = 0;
if (log_flags.guirpc_debug) {
msg_printf(0, MSG_INFO,
@ -1299,6 +1353,11 @@ int GUI_RPC_CONN::handle_rpc() {
mf.printf("</boinc_gui_rpc_reply>\n\003");
m.get_buf(p, n);
if (http_request) {
char buf[1024];
sprintf(buf, "HTTP/1.1 200 OK\nDate: Fri, 31 Dec 1999 23:59:59 GMT\nContent-Type: text/xml\nContent-Length: %d\n\n", n);
send(sock, buf, strlen(buf), 0);
}
if (p) {
send(sock, p, n, 0);
p[n-1]=0; // replace 003 with NULL