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