diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/Makefile | 9 | ||||
-rw-r--r-- | test/bsdsocket.c | 259 | ||||
-rw-r--r-- | test/bufbsdsocket.c (renamed from test/bsd_socket.c) | 142 |
3 files changed, 367 insertions, 43 deletions
diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..e96cb0f --- /dev/null +++ b/test/Makefile @@ -0,0 +1,9 @@ +.PHONY: all + +all: bsdsocket bsdsocket_nhd + +bsdsocket: bsdsocket.c ../picohttp.c ../picohttp.h + $(CC) -std=c99 -DHOST_DEBUG -O0 -g3 -I../ -o bsdsocket ../picohttp.c bsdsocket.c + +bsdsocket_nhd: bsdsocket.c ../picohttp.c ../picohttp.h + $(CC) -std=c99 -O0 -g3 -I../ -o bsdsocket_nhd ../picohttp.c bsdsocket.c diff --git a/test/bsdsocket.c b/test/bsdsocket.c new file mode 100644 index 0000000..5350db9 --- /dev/null +++ b/test/bsdsocket.c @@ -0,0 +1,259 @@ +#define _BSD_SOURCE + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include <unistd.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/ip.h> + +#include "../picohttp.h" + +int bsdsock_read(size_t count, void *buf, void *data) +{ + int fd = *((int*)data); + + ssize_t rb = 0; + ssize_t r = 0; + do { + r = read(fd, (unsigned char*)buf + rb, count-rb); + if( 0 < r ) { + rb += r; + continue; + } + if( !r ) { + break; + } + + if( EAGAIN == errno || + EWOULDBLOCK == errno ) { + usleep(100); + continue; + } + return -3 + errno; + } while( rb < count ); + return rb; +} + +int bsdsock_write(size_t count, void const *buf, void *data) +{ + int fd = *((int*)data); + + ssize_t wb = 0; + ssize_t w = 0; + do { + w = write(fd, (unsigned char*)buf + wb, count-wb); + if( 0 < w ) { + wb += w; + continue; + } + if( !w ) { + break; + } + + if( EAGAIN == errno || + EWOULDBLOCK == errno ) { + usleep(100); + continue; + } + return -3 + errno; + } while( wb < count ); + return wb; +} + +int bsdsock_getch(void *data) +{ + unsigned char ch; + int err; + if( 1 != (err = bsdsock_read(1, &ch, data)) ) + return err; + return ch; +} + +int bsdsock_putch(int ch, void *data) +{ + char ch_ = ch; + return bsdsock_write(1, &ch_, data); +} + +int bsdsock_flush(void* data) +{ + return 0; +} + +int sockfd = -1; + +void bye(void) +{ + fputs("exiting\n", stderr); + int const one = 1; + /* allows for immediate reuse of address:port + * after program termination */ + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + shutdown(sockfd, SHUT_RDWR); + close(sockfd); +} + +void rhRoot(struct picohttpRequest *req) +{ + fprintf(stderr, "handling request /%s\n", req->urltail); + + req->response.contenttype = "text/html"; + + char http_test[] = +"<html><head><title>handling request /</title></head><body>\n" +"<a href=\"/test\">/test</a>\n" +"<form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">\n" +"<label for=\"name\">Name: </label><input type=\"text\" name=\"name\"></input><br/>\n" +"<label for=\"file1\">File: </label><input type=\"file\" name=\"file1\"></input><br/>\n" +"<label for=\"file2\">File: </label><input type=\"file\" name=\"file2\"></input><br/>\n" +"<input type=\"submit\" value=\"Upload\"></input>\n" +"</form>\n" +"</body></html>\n"; + + picohttpResponseWrite(req, sizeof(http_test)-1, http_test); +} + +void rhTest(struct picohttpRequest *req) +{ + fprintf(stderr, "handling request /test%s\n", req->urltail); + char http_header[] = "HTTP/x.x 200 OK\r\nServer: picoweb\r\nContent-Type: text/text\r\n\r\n"; + http_header[5] = '0'+req->httpversion.major; + http_header[7] = '0'+req->httpversion.minor; + picohttpResponseWrite(req, sizeof(http_header)-1, http_header); + char http_test[] = "handling request /test"; + picohttpResponseWrite(req, sizeof(http_test)-1, http_test); + if(req->urltail) { + picohttpResponseWrite(req, strlen(req->urltail), req->urltail); + } +} + +void rhUpload(struct picohttpRequest *req) +{ + fprintf(stderr, "handling request /upload%s\n", req->urltail); + + if( PICOHTTP_CONTENTTYPE_MULTIPART_FORMDATA != req->query.contenttype ) + return; + + char http_test[] = "handling request /upload"; + + struct picohttpMultipart mp = picohttpMultipartStart(req); + + chdir("/tmp/uploadtest"); + while( !picohttpMultipartNext(&mp) ) { + fprintf(stderr, "\nprocessing form field \"%s\"\n", mp.disposition.name); + FILE *fil = fopen(mp.disposition.name, "wb"); + if(!fil) { + continue; + } + + for(int ch = picohttpMultipartGetch(&mp); + 0 <= ch; + ch = picohttpMultipartGetch(&mp) ) { + fputc(ch, fil); + + #if HOST_DEBUG + fputs("\e[32m", stderr); + switch(ch) { + case '\r': + fputs("[CR]", stderr); break; + case '\n': + fputs("[LF]", stderr); break; + + default: + fputc(ch, stderr); + } + fputs("\e[0m", stderr); + #endif/*HOST_DEBUG*/ + } + + fclose(fil); + if( !mp.finished ) { + break; + } + } + if( !mp.finished ) { + } + + picohttpResponseWrite(req, sizeof(http_test)-1, http_test); + if(req->urltail) { + picohttpResponseWrite(req, strlen(req->urltail), req->urltail); + } +} + +int main(int argc, char *argv[]) +{ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if( -1 == sockfd ) { + perror("socket"); + return -1; + } +#if 0 + if( atexit(bye) ) { + return -1; + } +#endif + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(8000), + .sin_addr = 0 + }; + + int const one = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if( -1 == bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) ) { + perror("bind"); + return -1; + } + + if( -1 == listen(sockfd, 2) ) { + perror("listen"); + return -1; + } + + for(;;) { + socklen_t addrlen = 0; + int confd = accept(sockfd, (struct sockaddr*)&addr, &addrlen); + if( -1 == confd ) { + if( EAGAIN == errno || + EWOULDBLOCK == errno ) { + usleep(1000); + continue; + } else { + perror("accept"); + return -1; + } + } + + struct picohttpIoOps ioops = { + .read = bsdsock_read, + .write = bsdsock_write, + .getch = bsdsock_getch, + .putch = bsdsock_putch, + .flush = bsdsock_flush, + .data = &confd + }; + + struct picohttpURLRoute routes[] = { + { "/test", 0, rhTest, 16, PICOHTTP_METHOD_GET }, + { "/upload", 0, rhUpload, 16, PICOHTTP_METHOD_POST }, + { "/|", 0, rhRoot, 0, PICOHTTP_METHOD_GET }, + { NULL, 0, 0, 0, 0 } + }; + + picohttpProcessRequest(&ioops, routes); + + shutdown(confd, SHUT_RDWR); + close(confd); + } + + return 0; +} + diff --git a/test/bsd_socket.c b/test/bufbsdsocket.c index 02ee592..22a4a99 100644 --- a/test/bsd_socket.c +++ b/test/bufbsdsocket.c @@ -6,81 +6,118 @@ #include <stdio.h> #include <errno.h> #include <string.h> +#include <assert.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> +#include <sys/ioctl.h> #include <netinet/ip.h> +#include <poll.h> #include "../picohttp.h" -int bsdsock_read(size_t count, char *buf, void *data) +#define SENDBUF_LEN 256 + +struct bufbsdsockData { + char * recvbuf; + size_t recvbuf_len; + size_t recvbuf_pos; + char sendbuf[SENDBUF_LEN]; + size_t sendbuf_pos; + int fd; +}; + +int bufbsdsock_read(size_t count, char *buf, void *data_) { - int fd = *((int*)data); - + struct bufbsdsockData *data = data_; + ssize_t rb = 0; ssize_t r = 0; do { - r = read(fd, buf+rb, count-rb); - if( 0 < r ) { - rb += r; - continue; - } - if( !r ) { - break; - } + size_t len = 0; + + if( !data->recvbuf || + data->recvbuf_pos >= data->recvbuf_len ) { + if( data->recvbuf ) + free( data->recvbuf ); + data->recvbuf_len = 0; + data->recvbuf_pos = 0; + + int avail = 0; + do { + struct pollfd pfd = { + .fd = data->fd, + .events = POLLIN | POLLPRI, + .revents = 0 + }; + + int const pret = poll(&pfd, 1, -1); + if( 0 >= pret ) { + return -1; + } + + assert(pfd.revents & (POLLIN | POLLPRI)); + + if( -1 == ioctl(data->fd, FIONREAD, &avail) ) { + perror("ioctl(FIONREAD)"); + return -1; + } + } while( !avail ); + + data->recvbuf = malloc( avail); + + int r; + while( 0 > (r = read(data->fd, data->recvbuf, avail)) ) { + if( EINTR == errno ) + continue; + + if( EAGAIN == errno || + EWOULDBLOCK == errno ) { + usleep(200); + continue; + } - if( EAGAIN == errno || - EWOULDBLOCK == errno ) { - usleep(100); - continue; + return -1; + } + data->recvbuf_len += r; } - return -3 + errno; + + len = data->recvbuf_len - data->recvbuf_pos; + if( len > count ) + len = count; + + rb += len; } while( rb < count ); return rb; } -int bsdsock_write(size_t count, char const *buf, void *data) +int bufbsdsock_write(size_t count, char const *buf, void *data) { int fd = *((int*)data); ssize_t wb = 0; ssize_t w = 0; do { - w = write(fd, buf+wb, count-wb); - if( 0 < w ) { - wb += w; - continue; - } - if( !w ) { - break; - } - - if( EAGAIN == errno || - EWOULDBLOCK == errno ) { - usleep(100); - continue; - } - return -3 + errno; } while( wb < count ); return wb; } -int16_t bsdsock_getch(void *data) +int16_t bufbsdsock_getch(void *data) { char ch; - if( 1 != bsdsock_read(1, &ch, data) ) + if( 1 != bufbsdsock_read(1, &ch, data) ) return -1; return ch; } -int bsdsock_putch(char ch, void *data) +int bufbsdsock_putch(char ch, void *data) { - return bsdsock_write(1, &ch, data); + return bufbsdsock_write(1, &ch, data); } -int bsdsock_flush(void* data) +int bufbsdsock_flush(void *data) { return 0; } @@ -104,7 +141,14 @@ void rhRoot(struct picohttpRequest *req) req->response.contenttype = "text/html"; - char http_test[] = "<html><head><title>handling request /</title></head>\n<body><a href=\"/test\">/test</a></body></html>\n"; + char http_test[] = +"<html><head><title>handling request /</title></head><body>\n" +"<a href=\"/test\">/test</a>" +"<form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">" +"<label for=\"file\">File: </label><input type=\"file\" name=\"file\"></input>" +"<input type=\"submit\" value=\"Upload\"></input>" +"</form>" +"</body></html>\n"; picohttpResponseWrite(req, sizeof(http_test)-1, http_test); } @@ -120,6 +164,17 @@ void rhTest(struct picohttpRequest *req) } } +void rhUpload(struct picohttpRequest *req) +{ + fprintf(stderr, "handling request /upload%s\n", req->urltail); + + char http_test[] = "handling request /upload"; + picohttpResponseWrite(req, sizeof(http_test)-1, http_test); + if(req->urltail) { + picohttpResponseWrite(req, strlen(req->urltail), req->urltail); + } +} + static uint8_t const favicon_ico[] = { 0x00,0x00,0x01,0x00,0x01,0x00,0x10,0x10,0x10,0x00,0x01,0x00,0x04,0x00,0x28,0x01, 0x00,0x00,0x16,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x20,0x00, @@ -198,17 +253,18 @@ int main(int argc, char *argv[]) } struct picohttpIoOps ioops = { - .read = bsdsock_read, - .write = bsdsock_write, - .getch = bsdsock_getch, - .putch = bsdsock_putch, - .flush = bsdsock_flush, + .read = bufbsdsock_read, + .write = bufbsdsock_write, + .getch = bufbsdsock_getch, + .putch = bufbsdsock_putch, + .flush = bufbsdsock_flush, .data = &confd }; struct picohttpURLRoute routes[] = { {"/favicon.ico|", 0, rhFavicon, 0, PICOHTTP_METHOD_GET}, { "/test", 0, rhTest, 16, PICOHTTP_METHOD_GET }, + { "/upload|", 0, rhUpload, 0, PICOHTTP_METHOD_GET }, { "/|", 0, rhRoot, 0, PICOHTTP_METHOD_GET }, { NULL, 0, 0, 0, 0 } }; |