#include "protocol.hfa" #define _GNU_SOURCE extern "C" { #include } #include #include // #include // Don't use stdio.h, too slow to compile extern "C" { int snprintf ( char * s, size_t n, const char * format, ... ); #include } #include #include #include "options.hfa" const char * http_msgs[] = { "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: %zu\n\n", "HTTP/1.1 400 Bad Request\nContent-Type: text/plain\nContent-Length: 0\n\n", "HTTP/1.1 404 Not Found\nContent-Type: text/plain\nContent-Length: 0\n\n", "HTTP/1.1 413 Payload Too Large\nContent-Type: text/plain\nContent-Length: 0\n\n", "HTTP/1.1 414 URI Too Long\nContent-Type: text/plain\nContent-Length: 0\n\n", }; _Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0]))); const int http_codes[] = { 200, 400, 404, 413, 414, }; _Static_assert( KNOWN_CODES == (sizeof(http_codes) / sizeof(http_codes[0]))); int code_val(HttpCode code) { return http_codes[code]; } static inline int answer( int fd, const char * it, int len) { while(len > 0) { // Call write int ret = write(fd, it, len); if( ret < 0 ) { if( errno != EAGAIN && errno != EWOULDBLOCK) abort( "'answer error' error: (%d) %s\n", (int)errno, strerror(errno) ); } // update it/len it += ret; len -= ret; } return 0; } int answer_error( int fd, HttpCode code ) { /* paranoid */ assert( code < KNOWN_CODES && code != OK200 ); int idx = (int)code; return answer( fd, http_msgs[idx], strlen( http_msgs[idx] ) ); } int answer_header( int fd, size_t size ) { const char * fmt = http_msgs[OK200]; int len = 100; char buffer[len]; len = snprintf(buffer, len, fmt, size); return answer( fd, buffer, len ); } [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) { char * it = buffer; size_t count = len - 1; int rlen = 0; READ: for() { int ret = cfa_read(fd, (void*)it, count, 0, -1`s, 0p, 0p); if(ret == 0 ) return [OK200, true, 0, 0]; if(ret < 0 ) { if( errno == EAGAIN || errno == EWOULDBLOCK) continue READ; abort( "read error: (%d) %s\n", (int)errno, strerror(errno) ); } it[ret + 1] = '\0'; rlen += ret; if( strstr( it, "\r\n\r\n" ) ) break; it += ret; count -= ret; if( count < 1 ) return [E414, false, 0, 0]; } printf("%.*s\n", rlen, buffer); it = buffer; int ret = memcmp(it, "GET /", 5); if( ret != 0 ) return [E400, false, 0, 0]; it += 5; char * end = strstr( it, " " ); return [OK200, false, it, end - it]; } void sendfile( int pipe[2], int fd, int ans_fd, size_t count ) { off_t offset = 0; ssize_t ret; SPLICE1: while(count > 0) { ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, SPLICE_F_MOVE | SPLICE_F_MORE, 0, -1`s, 0p, 0p); if( ret < 0 ) { if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE1; abort( "splice [0] error: (%d) %s\n", (int)errno, strerror(errno) ); } count -= ret; offset += ret; size_t in_pipe = ret; SPLICE2: while(in_pipe > 0) { ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, SPLICE_F_MOVE | SPLICE_F_MORE, 0, -1`s, 0p, 0p); if( ret < 0 ) { if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE2; abort( "splice [1] error: (%d) %s\n", (int)errno, strerror(errno) ); } in_pipe -= ret; } } }