| Line 1... |
Line 1... |
| 1 |
/*
|
1 |
/*
|
| 2 |
* R : A Computer Language for Statistical Data Analysis
|
2 |
* R : A Computer Language for Statistical Data Analysis
|
| 3 |
* Copyright (C) 2009-11 The R Core Team.
|
3 |
* Copyright (C) 2009-12 The R Core Team.
|
| 4 |
*
|
4 |
*
|
| 5 |
* This program is free software; you can redistribute it and/or modify
|
5 |
* This program is free software; you can redistribute it and/or modify
|
| 6 |
* it under the terms of the GNU General Public License as published by
|
6 |
* it under the terms of the GNU General Public License as published by
|
| 7 |
* the Free Software Foundation; either version 2 of the License, or
|
7 |
* the Free Software Foundation; either version 2 of the License, or
|
| 8 |
* (at your option) any later version.
|
8 |
* (at your option) any later version.
|
| Line 166... |
Line 166... |
| 166 |
#define CONTENT_TYPE 0x40 /* message has a specific content type set */
|
166 |
#define CONTENT_TYPE 0x40 /* message has a specific content type set */
|
| 167 |
#define CONTENT_FORM_UENC 0x80 /* message content type is application/x-www-form-urlencoded */
|
167 |
#define CONTENT_FORM_UENC 0x80 /* message content type is application/x-www-form-urlencoded */
|
| 168 |
|
168 |
|
| 169 |
struct buffer {
|
169 |
struct buffer {
|
| 170 |
struct buffer *next, *prev;
|
170 |
struct buffer *next, *prev;
|
| 171 |
int size, length;
|
171 |
size_t size, length;
|
| 172 |
char data[1];
|
172 |
char data[1];
|
| 173 |
};
|
173 |
};
|
| 174 |
|
174 |
|
| 175 |
/* --- connection/worker structure holding all data for an active connection --- */
|
175 |
/* --- connection/worker structure holding all data for an active connection --- */
|
| 176 |
typedef struct httpd_conn {
|
176 |
typedef struct httpd_conn {
|
| Line 182... |
Line 182... |
| 182 |
InputHandler *ih; /* worker input handler */
|
182 |
InputHandler *ih; /* worker input handler */
|
| 183 |
#endif
|
183 |
#endif
|
| 184 |
char line_buf[LINE_BUF_SIZE]; /* line buffer (used for request and headers) */
|
184 |
char line_buf[LINE_BUF_SIZE]; /* line buffer (used for request and headers) */
|
| 185 |
char *url, *body; /* URL and request body */
|
185 |
char *url, *body; /* URL and request body */
|
| 186 |
char *content_type; /* content type (if set) */
|
186 |
char *content_type; /* content type (if set) */
|
| 187 |
unsigned int line_pos, body_pos; /* positions in the buffers */
|
187 |
size_t line_pos, body_pos; /* positions in the buffers */
|
| 188 |
long content_length; /* desired content length */
|
188 |
long content_length; /* desired content length */
|
| 189 |
char part, method, attr; /* request part, method and connection attributes */
|
189 |
char part, method, attr; /* request part, method and connection attributes */
|
| 190 |
struct buffer *headers; /* buffer holding header lines */
|
190 |
struct buffer *headers; /* buffer holding header lines */
|
| 191 |
} httpd_conn_t;
|
191 |
} httpd_conn_t;
|
| 192 |
|
192 |
|
| Line 349... |
Line 349... |
| 349 |
extern int R_ignore_SIGPIPE; /* defined in src/main/main.c on unix */
|
349 |
extern int R_ignore_SIGPIPE; /* defined in src/main/main.c on unix */
|
| 350 |
#else
|
350 |
#else
|
| 351 |
static int R_ignore_SIGPIPE; /* for simplicity of the code below */
|
351 |
static int R_ignore_SIGPIPE; /* for simplicity of the code below */
|
| 352 |
#endif
|
352 |
#endif
|
| 353 |
|
353 |
|
| 354 |
static int send_response(SOCKET s, const char *buf, unsigned int len)
|
354 |
static int send_response(SOCKET s, const char *buf, size_t len)
|
| 355 |
{
|
355 |
{
|
| 356 |
unsigned int i = 0;
|
356 |
unsigned int i = 0;
|
| 357 |
/* we have to tell R to ignore SIGPIPE otherwise it can raise an error
|
357 |
/* we have to tell R to ignore SIGPIPE otherwise it can raise an error
|
| 358 |
and get us into deep trouble */
|
358 |
and get us into deep trouble */
|
| 359 |
R_ignore_SIGPIPE = 1;
|
359 |
R_ignore_SIGPIPE = 1;
|
| 360 |
while (i < len) {
|
360 |
while (i < len) {
|
| 361 |
int n = send(s, buf + i, len - i, 0);
|
361 |
ssize_t n = send(s, buf + i, len - i, 0);
|
| 362 |
if (n < 1) {
|
362 |
if (n < 1) {
|
| 363 |
R_ignore_SIGPIPE = 0;
|
363 |
R_ignore_SIGPIPE = 0;
|
| 364 |
return -1;
|
364 |
return -1;
|
| 365 |
}
|
365 |
}
|
| 366 |
i += n;
|
366 |
i += n;
|
| Line 371... |
Line 371... |
| 371 |
|
371 |
|
| 372 |
/* sends HTTP/x.x plus the text (which should be of the form " XXX ...") */
|
372 |
/* sends HTTP/x.x plus the text (which should be of the form " XXX ...") */
|
| 373 |
static int send_http_response(httpd_conn_t *c, const char *text) {
|
373 |
static int send_http_response(httpd_conn_t *c, const char *text) {
|
| 374 |
char buf[96];
|
374 |
char buf[96];
|
| 375 |
const char *s = HTTP_SIG(c);
|
375 |
const char *s = HTTP_SIG(c);
|
| 376 |
int l = strlen(text), res;
|
376 |
size_t l = strlen(text);
|
| - |
|
377 |
ssize_t res;
|
| 377 |
/* reduce the number of packets by sending the payload en-block from buf */
|
378 |
/* reduce the number of packets by sending the payload en-block from buf */
|
| 378 |
if (l < sizeof(buf) - 10) {
|
379 |
if (l < sizeof(buf) - 10) {
|
| 379 |
strcpy(buf, s);
|
380 |
strcpy(buf, s);
|
| 380 |
strcpy(buf + 8, text);
|
381 |
strcpy(buf + 8, text);
|
| 381 |
return send_response(c->sock, buf, l + 8);
|
382 |
return send_response(c->sock, buf, l + 8);
|
| Line 665... |
Line 666... |
| 665 |
send_response(c->sock, buf, strlen(buf));
|
666 |
send_response(c->sock, buf, strlen(buf));
|
| 666 |
if (c->method != METHOD_HEAD) {
|
667 |
if (c->method != METHOD_HEAD) {
|
| 667 |
fbuf = (char*) malloc(32768);
|
668 |
fbuf = (char*) malloc(32768);
|
| 668 |
if (fbuf) {
|
669 |
if (fbuf) {
|
| 669 |
while (fsz > 0 && !feof(f)) {
|
670 |
while (fsz > 0 && !feof(f)) {
|
| 670 |
int rd = (fsz > 32768) ? 32768 : fsz;
|
671 |
size_t rd = (fsz > 32768) ? 32768 : fsz;
|
| 671 |
if (fread(fbuf, 1, rd, f) != rd) {
|
672 |
if (fread(fbuf, 1, rd, f) != rd) {
|
| 672 |
free(fbuf);
|
673 |
free(fbuf);
|
| 673 |
UNPROTECT(7);
|
674 |
UNPROTECT(7);
|
| 674 |
c->attr |= CONNECTION_CLOSE;
|
675 |
c->attr |= CONNECTION_CLOSE;
|
| 675 |
return;
|
676 |
return;
|
| Line 736... |
Line 737... |
| 736 |
|
737 |
|
| 737 |
/* this function is called to fetch new data from the client
|
738 |
/* this function is called to fetch new data from the client
|
| 738 |
* connection socket and process it */
|
739 |
* connection socket and process it */
|
| 739 |
static void worker_input_handler(void *data) {
|
740 |
static void worker_input_handler(void *data) {
|
| 740 |
httpd_conn_t *c = (httpd_conn_t*) data;
|
741 |
httpd_conn_t *c = (httpd_conn_t*) data;
|
| 741 |
int n;
|
- |
|
| 742 |
|
742 |
|
| 743 |
DBG(printf("worker_input_handler, data=%p\n", data));
|
743 |
DBG(printf("worker_input_handler, data=%p\n", data));
|
| 744 |
if (!c) return;
|
744 |
if (!c) return;
|
| 745 |
|
745 |
|
| 746 |
DBG(printf("input handler for worker %p (sock=%d, part=%d, method=%d, line_pos=%d)\n", (void*) c, (int)c->sock, (int)c->part, (int)c->method, (int)c->line_pos));
|
746 |
DBG(printf("input handler for worker %p (sock=%d, part=%d, method=%d, line_pos=%d)\n", (void*) c, (int)c->sock, (int)c->part, (int)c->method, (int)c->line_pos));
|
| Line 755... |
Line 755... |
| 755 |
* happen, because clients should wait for the response and even
|
755 |
* happen, because clients should wait for the response and even
|
| 756 |
* if they don't it's unlikely that both requests get combined
|
756 |
* if they don't it's unlikely that both requests get combined
|
| 757 |
* into one packet. */
|
757 |
* into one packet. */
|
| 758 |
if (c->part < PART_BODY) {
|
758 |
if (c->part < PART_BODY) {
|
| 759 |
char *s = c->line_buf;
|
759 |
char *s = c->line_buf;
|
| 760 |
n = recv(c->sock, c->line_buf + c->line_pos, LINE_BUF_SIZE - c->line_pos - 1, 0);
|
760 |
ssize_t n = recv(c->sock, c->line_buf + c->line_pos,
|
| - |
|
761 |
LINE_BUF_SIZE - c->line_pos - 1, 0);
|
| 761 |
DBG(printf("[recv n=%d, line_pos=%d, part=%d]\n", n, c->line_pos, (int)c->part));
|
762 |
DBG(printf("[recv n=%d, line_pos=%d, part=%d]\n", n, c->line_pos, (int)c->part));
|
| 762 |
if (n < 0) { /* error, scrape this worker */
|
763 |
if (n < 0) { /* error, scrape this worker */
|
| 763 |
remove_worker(c);
|
764 |
remove_worker(c);
|
| 764 |
return;
|
765 |
return;
|
| 765 |
}
|
766 |
}
|
| Line 849... |
Line 850... |
| 849 |
if (*s == '\r') *(s++) = 0;
|
850 |
if (*s == '\r') *(s++) = 0;
|
| 850 |
if (*s == '\n') *(s++) = 0;
|
851 |
if (*s == '\n') *(s++) = 0;
|
| 851 |
DBG(printf("complete line: {%s}\n", bol));
|
852 |
DBG(printf("complete line: {%s}\n", bol));
|
| 852 |
if (c->part == PART_REQUEST) {
|
853 |
if (c->part == PART_REQUEST) {
|
| 853 |
/* --- process request line --- */
|
854 |
/* --- process request line --- */
|
| 854 |
unsigned int rll = strlen(bol); /* request line length */
|
855 |
size_t rll = strlen(bol); /* request line length */
|
| 855 |
char *url = bol + 5;
|
856 |
char *url = bol + 5;
|
| 856 |
if (rll < 14 || strncmp(bol + rll - 9, " HTTP/1.", 8)) { /* each request must have at least 14 characters [GET / HTTP/1.0] and have HTTP/1.x */
|
857 |
if (rll < 14 || strncmp(bol + rll - 9, " HTTP/1.", 8)) { /* each request must have at least 14 characters [GET / HTTP/1.0] and have HTTP/1.x */
|
| 857 |
send_response(c->sock, "HTTP/1.0 400 Bad Request\r\n\r\n", 28);
|
858 |
send_response(c->sock, "HTTP/1.0 400 Bad Request\r\n\r\n", 28);
|
| 858 |
remove_worker(c);
|
859 |
remove_worker(c);
|
| 859 |
return;
|
860 |
return;
|
| Line 875... |
Line 876... |
| 875 |
/* --- process headers --- */
|
876 |
/* --- process headers --- */
|
| 876 |
char *k = bol;
|
877 |
char *k = bol;
|
| 877 |
if (!c->headers)
|
878 |
if (!c->headers)
|
| 878 |
c->headers = alloc_buffer(1024, NULL);
|
879 |
c->headers = alloc_buffer(1024, NULL);
|
| 879 |
if (c->headers) { /* record the header line in the buffer */
|
880 |
if (c->headers) { /* record the header line in the buffer */
|
| 880 |
int l = strlen(bol);
|
881 |
size_t l = strlen(bol);
|
| 881 |
if (l) { /* this should be really always true */
|
882 |
if (l) { /* this should be really always true */
|
| 882 |
if (c->headers->length + l + 1 > c->headers->size) { /* not enough space? */
|
883 |
if (c->headers->length + l + 1 > c->headers->size) { /* not enough space? */
|
| 883 |
int fits = c->headers->size - c->headers->length;
|
884 |
size_t fits = c->headers->size - c->headers->length;
|
| 884 |
if (fits) memcpy(c->headers->data + c->headers->length, bol, fits);
|
885 |
if (fits) memcpy(c->headers->data + c->headers->length, bol, fits);
|
| 885 |
if (alloc_buffer(2048, c->headers)) {
|
886 |
if (alloc_buffer(2048, c->headers)) {
|
| 886 |
c->headers = c->headers->next;
|
887 |
c->headers = c->headers->next;
|
| 887 |
memcpy(c->headers->data, bol + fits, l - fits);
|
888 |
memcpy(c->headers->data, bol + fits, l - fits);
|
| 888 |
c->headers->length = l - fits;
|
889 |
c->headers->length = l - fits;
|
| Line 937... |
Line 938... |
| 937 |
}
|
938 |
}
|
| 938 |
}
|
939 |
}
|
| 939 |
if (c->part == PART_BODY && c->body) { /* BODY - this branch always returns */
|
940 |
if (c->part == PART_BODY && c->body) { /* BODY - this branch always returns */
|
| 940 |
if (c->body_pos < c->content_length) { /* need to receive more ? */
|
941 |
if (c->body_pos < c->content_length) { /* need to receive more ? */
|
| 941 |
DBG(printf("BODY: body_pos=%d, content_length=%ld\n", c->body_pos, c->content_length));
|
942 |
DBG(printf("BODY: body_pos=%d, content_length=%ld\n", c->body_pos, c->content_length));
|
| 942 |
n = recv(c->sock, c->body + c->body_pos, c->content_length - c->body_pos, 0);
|
943 |
ssize_t n = recv(c->sock, c->body + c->body_pos,
|
| - |
|
944 |
c->content_length - c->body_pos, 0);
|
| 943 |
DBG(printf(" [recv n=%d - had %u of %lu]\n", n, c->body_pos, c->content_length));
|
945 |
DBG(printf(" [recv n=%d - had %u of %lu]\n", n, c->body_pos, c->content_length));
|
| 944 |
c->line_pos = 0;
|
946 |
c->line_pos = 0;
|
| 945 |
if (n < 0) { /* error, scrap this worker */
|
947 |
if (n < 0) { /* error, scrap this worker */
|
| 946 |
remove_worker(c);
|
948 |
remove_worker(c);
|
| 947 |
return;
|
949 |
return;
|
| Line 1007... |
Line 1009... |
| 1007 |
c->attr = 0;
|
1009 |
c->attr = 0;
|
| 1008 |
c->content_length = 0;
|
1010 |
c->content_length = 0;
|
| 1009 |
return;
|
1011 |
return;
|
| 1010 |
}
|
1012 |
}
|
| 1011 |
}
|
1013 |
}
|
| 1012 |
n = recv(c->sock, c->line_buf + c->line_pos, LINE_BUF_SIZE - c->line_pos - 1, 0);
|
1014 |
ssize_t n = recv(c->sock, c->line_buf + c->line_pos,
|
| - |
|
1015 |
LINE_BUF_SIZE - c->line_pos - 1, 0);
|
| 1013 |
if (n < 0) { /* error, scrap this worker */
|
1016 |
if (n < 0) { /* error, scrap this worker */
|
| 1014 |
remove_worker(c);
|
1017 |
remove_worker(c);
|
| 1015 |
return;
|
1018 |
return;
|
| 1016 |
}
|
1019 |
}
|
| 1017 |
if (n == 0) { /* connection closed -> try to process and then remove */
|
1020 |
if (n == 0) { /* connection closed -> try to process and then remove */
|