The R Project SVN R

Rev

Rev 59039 | Rev 59338 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 59039 Rev 59184
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 */