aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Makefile9
-rw-r--r--test/bsdsocket.c259
-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 }
};