mirror of https://github.com/BOINC/boinc.git
- 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:
parent
fe67e7c4e9
commit
87a8fb1aee
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue