crossroads

Git mirror of https://crossroads.e-tunity.com/
git clone git://git.finwo.net/app/crossroads
Log | Files | Refs

httpserve.c (7200B)


      1 /*************************************************************************
      2  * This file is part of Crosroads 1.23, a load balancer and fail over
      3  * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
      4  * Visit http://crossroads.e-tunity.com for information.
      5  *************************************************************************/
      6 #include "crossroads.h"
      7 
      8 void http_serve (int clientsock) {
      9     int serversock = -1, is_continuation, i;
     10     HttpHeader *clientreq, *serverresp;
     11     int client_persisting, server_persisting;
     12     unsigned char *cp;
     13     unsigned size;
     14 
     15     /* Fork off a servicer if we're in daemon mode. */
     16     if (fork_tcp_servicer(-1))
     17 	return;
     18 
     19     /* We're the child branch now of fork_tcp_servicer().
     20      * Here's the logic of the HTTP services.
     21      * - Get the client's request;
     22      * - If we're not yet connected to a back end: determine the back
     23      *   end and connect to it
     24      * - Apply all server-directed headers
     25      * - Send client's request to the server
     26      * - Read back the server's response
     27      * - Apply all client-directed headers
     28      * - Send the server's response to the client
     29      * - Redo from start; this might be a Keep-Alive connection
     30      */
     31 
     32     while (1) {
     33 	/* Assume both client and server want to persist. */
     34 	client_persisting = server_persisting = 1;
     35 	
     36 	/* Get the initial client headers */
     37 	clientreq = http_header_new();
     38 	http_header_read (clientreq, clientsock, dir_client_to_server);
     39 	
     40 	/* Determine the back end if necessary. */
     41 	if (serversock == -1) {
     42 	    if ( (serversock = http_serversocket (clientreq,
     43 						  &is_continuation)) < 1 )
     44 		http_error (clientsock);
     45 	    
     46 	    incr_client_count();
     47 	    if (is_continuation)
     48 		log_activity_continuation();
     49 	    else
     50 		log_activity_start ();
     51 	}
     52 	
     53 	/* Put all server-directed headers in place. */
     54 	for (i = 0;
     55 	     i < activeservice->backend[current_backend].naddserverheader;
     56 	     i++)
     57 	    http_header_addheader (clientreq,
     58 	        activeservice->backend[current_backend].addserverheader[i]);
     59 	for (i = 0;
     60 	     i < activeservice->backend[current_backend].nsetserverheader;
     61 	     i++)
     62 	    http_header_setheader (clientreq,
     63   	        activeservice->backend[current_backend].setserverheader[i]);
     64 	for (i = 0;
     65 	     i < activeservice->backend[current_backend].nappendserverheader;
     66 	     i++)
     67 	    http_header_appendheader (clientreq,
     68 	        activeservice->backend[current_backend].appendserverheader[i]);
     69 
     70 	/* See RFC2616. We're actually a proxy here. Clients that talk
     71 	 * HTTP/1.0 MUST be treated as single shot connection clients, even
     72 	 * when they specify Connection: Keep-Alive. */
     73 	if (http_header_httpver (clientreq) < 1.1) {
     74 	    msg ("Service %s: Client talks HTTP < 1.1, forcing closing "
     75 		 "connections", activeservice->name);
     76 	    http_header_setheader (clientreq, "Connection: close");
     77 	    http_header_setheader (clientreq, "Proxy-Connection: close");
     78 	    client_persisting = 0;
     79 	} else if (http_header_connectiontype (clientreq) == con_close) {
     80 	    msg ("Service %s: Client asks for connection closing",
     81 		 activeservice->name);
     82 	    client_persisting = 0;
     83 	}
     84 
     85 	/* Send client's headers to the back end. */
     86 	http_header_write (clientreq, serversock, dir_client_to_server);
     87 	
     88 	/* Copy body from client to server */
     89 	http_copy (clientreq, clientsock, serversock, dir_client_to_server);
     90 	if ( (cp = net_buffer (dir_client_to_server, &size)) )
     91 	    net_write (serversock, cp, size, 0);
     92 	
     93 	/* Get server response. */
     94 	serverresp = http_header_new();
     95 	http_header_read (serverresp, serversock, dir_server_to_client);
     96 
     97 	/* According to RFC1616,  we should convert chunked output
     98 	 * from the server to one big message.
     99 	 * We won't do that here, it breaks streaming.
    100 	 * But we will close connections in the case of chunked transfer. */
    101 	if (client_persisting &&
    102 	    http_header_val (serverresp, "transfer-encoding")) {
    103 	    msg ("Service %s: Server is sending chunks, forcing singleshot",
    104 		 activeservice->name);
    105 	    server_persisting = 0;
    106 	    http_header_setheader (serverresp, "Connection: close");
    107 	    http_header_setheader (serverresp, "Proxy-Connection: close");
    108 	}
    109 
    110 	/* Put client-directed headers in place. */
    111 	for (i = 0;
    112 	     i < activeservice->backend[current_backend].naddclientheader;
    113 	     i++)
    114 	    http_header_addheader (serverresp,
    115 	        activeservice->backend[current_backend].addclientheader[i]);
    116 	for (i = 0;
    117 	     i < activeservice->backend[current_backend].nsetclientheader;
    118 	     i++)
    119 	    http_header_setheader (serverresp,
    120 	        activeservice->backend[current_backend].setclientheader[i]);
    121 	for (i = 0;
    122 	     i < activeservice->backend[current_backend].nappendclientheader;
    123 	     i++)
    124 	    http_header_appendheader (serverresp,
    125 	        activeservice->backend[current_backend].appendclientheader[i]);
    126 
    127 	/* According to RFC1616,  we should convert chunked output
    128 	 * from the server to one big message.
    129 	 * We won't do that here, it breaks streaming.
    130 	 * But we will close connections in the case of chunked transfer. */
    131 	if (client_persisting &&
    132 	    http_header_val (serverresp, "transfer-encoding")) {
    133 	    msg ("Service %s: Server is sending chunks, forcing singleshot",
    134 		 activeservice->name);
    135 	    server_persisting = 0;
    136 	    client_persisting = 0;
    137 	    http_header_setheader (serverresp, "Connection: close");
    138 	    http_header_setheader (serverresp, "Proxy-Connection: close");
    139 	}
    140 
    141 	/* If the server wants to close the connection, then we must
    142 	 * inform the client. */
    143 	if (client_persisting) {
    144 	    if (http_header_httpver (serverresp) < 1.1) {
    145 		msg ("Service %s: Server talks HTTP < 1.1, forcing closing "
    146 		     "connections", activeservice->name);
    147 		http_header_setheader (serverresp, "Connection: close");
    148 		http_header_setheader (serverresp, "Proxy-Connection: close");
    149 		server_persisting = 0;
    150 	    } else if (http_header_connectiontype (serverresp) == con_close) {
    151 		msg ("Service %s: Server asks for connection closing",
    152 		 activeservice->name);
    153 		http_header_setheader (serverresp, "Connection: close");
    154 		http_header_setheader (serverresp, "Proxy-Connection: close");
    155 		server_persisting = 0;
    156 	    }
    157 	}
    158 	
    159 	/* Send server headers to the client. */
    160 	http_header_write (serverresp, clientsock, dir_server_to_client);
    161 	
    162 	/* Copy body from server to cliet and flush network buffers if any */
    163 	http_copy (serverresp, serversock, clientsock, dir_server_to_client);
    164 	if ( (cp = net_buffer (dir_server_to_client, &size)) )
    165 	    net_write (clientsock, cp, size, 0);
    166 
    167 	/* Free up info from this request/response chat. */
    168 	http_header_free (clientreq);
    169 	http_header_free (serverresp);
    170 
    171 	/* Should we loop around? Go to copy-thru mode if either the
    172 	 * client or the server wants to stop. */
    173 	if (!client_persisting || !server_persisting) {
    174 	    msg ("Service %s: non-persistent connection",
    175 		 activeservice->name);
    176 	    break;
    177 	}
    178 	
    179 	msg ("Service %s: Analyzing following requests over same TCP link",
    180 	     activeservice->name);
    181     }
    182 
    183     /* Copy through all that arrives on back end or client.
    184      * This doesn't return... */
    185     msg ("Service %s: HTTP service done analyzing, entering copy-thru mode",
    186 	 activeservice->name);
    187 
    188     /* This doesn't return */
    189     copysockets (clientsock, serversock);
    190 
    191 }