httpgw finally builds
[swift-upb.git] / httpgw.cpp
1 #include "swift.h"
2
3 using namespace swift;
4
5 #define HTTPGW_MAX_CLIENT 128
6
7 enum {
8     HTTPGW_RANGE=0,
9     HTTPGW_MAX_HEADER=1
10 };
11 char * HTTPGW_HEADERS[HTTPGW_MAX_HEADER] = {
12     "Content-Range"
13 };
14
15
16 struct http_gw_t {
17     uint64_t offset;
18     uint64_t tosend;
19     int      transfer;
20     SOCKET   sink;
21     char*    headers[HTTPGW_MAX_HEADER];
22 } http_requests[HTTPGW_MAX_CLIENT];
23
24
25 int http_gw_reqs_open = 0;
26
27 void HttpGwNewRequestCallback (SOCKET http_conn);
28 void HttpGwNewRequestCallback (SOCKET http_conn);
29
30 http_gw_t* HttpGwFindRequest (SOCKET sock) {
31     for(int i=0; i<http_gw_reqs_open; i++)
32         if (http_requests[i].sink==sock)
33             return http_requests+i;
34     return NULL;
35 }
36
37
38 void HttpGwCloseConnection (SOCKET sock) {
39     http_gw_t* req = HttpGwFindRequest(sock);
40     if (req) {
41         for(int i=0; i<HTTPGW_MAX_HEADER; i++)
42             if (req->headers[i]) {
43                 free(req->headers[i]);
44                 req->headers[i] = NULL;
45             }
46         *req = http_requests[http_gw_reqs_open--];
47     }
48     swift::close_socket(sock);
49 }
50  
51
52 void HttpGwMayWriteCallback (SOCKET sink) {
53     http_gw_t* req = HttpGwFindRequest(sink);
54     uint64_t complete = swift::SeqComplete(req->transfer);
55     if (complete>req->offset) { // send data
56         char buf[1<<12];
57         uint64_t tosend = std::min((uint64_t)1<<12,complete-req->offset);
58         size_t rd = read(req->transfer,buf,tosend); // hope it is cached
59         if (rd<0) {
60             HttpGwCloseConnection(sink);
61             return;
62         }
63         size_t wn = send(sink, buf, rd, 0);
64         if (wn<0) {
65             HttpGwCloseConnection(sink);
66             return;
67         }
68         req->offset += wn;
69         req->tosend -= wn;
70     } else {
71         if (swift::IsComplete(req->transfer)) { // done; wait for new request
72             socket_callbacks_t wait_new_req(req->sink,HttpGwNewRequestCallback,NULL,HttpGwCloseConnection);
73             swift::Listen3rdPartySocket (wait_new_req);
74         } else { // wait for data
75             socket_callbacks_t wait_swift_data(req->sink,NULL,NULL,HttpGwCloseConnection);
76             swift::Listen3rdPartySocket(wait_swift_data);
77         }
78     }
79 }
80
81
82 void HttpGwSwiftProgressCallback (int transfer, bin64_t bin) {
83     for (int httpc=0; httpc<http_gw_reqs_open; httpc++)
84         if (http_requests[httpc].transfer==transfer)
85             if ( (bin.offset()<<10) == http_requests[httpc].offset ) {
86                 socket_callbacks_t maywrite_callbacks
87                         (http_requests[httpc].sink,NULL,HttpGwMayWriteCallback,HttpGwCloseConnection);
88                 Listen3rdPartySocket (maywrite_callbacks);
89             }
90 }
91
92
93 void HttpGwFirstProgressCallback (int transfer, bin64_t bin) {
94     printf("200 OK\r\n");
95     printf("Content-Length: value\r\n");
96     swift::RemoveProgressCallback(transfer,&HttpGwFirstProgressCallback);
97     swift::AddProgressCallback(transfer,&HttpGwSwiftProgressCallback);
98     HttpGwSwiftProgressCallback(transfer,bin);
99 }
100
101
102 void HttpGwNewRequestCallback (SOCKET http_conn){
103     http_gw_t* req = http_requests + http_gw_reqs_open++;
104     req->sink = http_conn;
105     // read headers - the thrilling part
106     // we surely do not support pipelining => one request at a time
107     #define HTTPGW_MAX_REQ_SIZE 1024
108     char buf[HTTPGW_MAX_REQ_SIZE+1];
109     int rd = recv(http_conn,buf,HTTPGW_MAX_REQ_SIZE,0);
110     if (rd<=0) { // if conn is closed by the peer, rd==0
111         HttpGwCloseConnection(http_conn);
112         return;
113     }
114     buf[rd] = 0;
115     // HTTP request line
116     char* reqline = strtok(buf,"\r\n");
117     char method[16], url[512], version[16], crlf[5];
118     if (4!=sscanf(reqline,"%16s %512s %16s%4[\n\r]",method,url,version,crlf)) {
119         HttpGwCloseConnection(http_conn);
120         return;
121     }
122     // HTTP header fields
123     char* headerline;
124     while (headerline=strtok(NULL,"\n\r")) {
125         char header[128], value[256];
126         if (3!=sscanf(headerline,"%120[^: \r\n]: %250[^\r\n]%4[\r\n]",header,value,crlf)) {
127             HttpGwCloseConnection(http_conn);
128             return;
129         }
130         for(int i=0; i<HTTPGW_MAX_HEADER; i++)
131             if (0==strcasecmp(HTTPGW_HEADERS[i],header) && !req->headers[i])
132                 req->headers[i] = strdup(value);
133     }
134     // parse URL
135     char * hashch=strtok(url,"/"), hash[41];
136     while (hashch && (1!=sscanf(hashch,"%40[0123456789abcdefABCDEF]",hash) || strlen(hash)!=40))
137         hashch = strtok(NULL,"/");
138     if (strlen(hash)!=40) {
139         HttpGwCloseConnection(http_conn);
140         return;
141     }
142     // initiate transmission
143     int file = swift::Open(hash,hash);
144     // find/create transfer
145     swift::AddProgressCallback(file,&HttpGwFirstProgressCallback);
146     // write response header
147     req->offset = 0;
148     req->tosend = 10000;
149     req->transfer = file;
150     socket_callbacks_t install (http_conn,NULL,NULL,HttpGwCloseConnection);
151     swift::Listen3rdPartySocket(install);
152 }
153
154
155 // be liberal in what you do, be conservative in what you accept
156 void HttpGwNewConnectionCallback (SOCKET serv) {
157     Address client_address;
158     socklen_t len;
159     SOCKET conn = accept 
160         (serv, (sockaddr*) & (client_address.addr), &len);
161     if (conn==INVALID_SOCKET) {
162         print_error("client conn fails");
163         return;
164     }
165     make_socket_nonblocking(conn);
166     // submit 3rd party socket to the swift loop
167     socket_callbacks_t install
168         (conn,HttpGwNewRequestCallback,NULL,HttpGwCloseConnection);
169     swift::Listen3rdPartySocket(install);
170 }
171
172
173 void HttpGwError (SOCKET s) {
174     print_error("everything fucked up");
175 }
176
177
178 SOCKET InstallHTTPGateway (Address bind_to) {
179     SOCKET fd;
180     #define gw_ensure(x) { if (!(x)) { \
181     print_error("http binding fails"); close_socket(fd); \
182     return INVALID_SOCKET; } }
183     gw_ensure ( (fd=socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET );
184     gw_ensure ( 0==bind(fd, (sockaddr*)&(bind_to.addr), sizeof(struct sockaddr_in)) );
185     gw_ensure (make_socket_nonblocking(fd));
186     gw_ensure ( 0==listen(fd,8) );
187     socket_callbacks_t install(fd,HttpGwNewConnectionCallback,NULL,HttpGwError);
188     gw_ensure (swift::Listen3rdPartySocket(install));
189 }