crossroads

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

httpcopy.c (3503B)


      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 static void copy (int src, int dst, int dir, unsigned tot) {
      9     unsigned ncopied = 0, to_copy, bytes;
     10     unsigned char *buf;
     11 
     12     while (ncopied < tot) {
     13 	/* Here's how many bytes we should shuttle to and fro.
     14 	 * This is the remaining count, or if the buffer is too small
     15 	 * for that, the buffer size. */
     16 	to_copy = tot - ncopied;
     17 	if (to_copy > TCP_BUFSZ)
     18 	    to_copy = TCP_BUFSZ;
     19 
     20 	buf = net_bufread (src, to_copy, &bytes, dir == dir_client_to_server);
     21 	net_write (dst, buf, bytes, dir == dir_client_to_server);
     22 	ncopied += bytes;
     23 
     24 	/* msg ("Copied 0x%x (%d) bytes of 0x%x (%d) total",
     25 	     ncopied, ncopied, tot, tot);
     26 	*/
     27     }
     28 }
     29 
     30 unsigned getchunk (int sock, int dest, CopyDirection dir) {
     31     unsigned ret = 0;
     32     unsigned char *cp;
     33     char *hexbuf = 0;
     34     int in_number = 1;
     35 
     36     /* We match
     37      *           <hex-chunksize> <any-mush> [\r] \n
     38      * while copying all to the other socket, and return the
     39      * chunk size */
     40     while (1) {
     41 	cp = net_bufread (sock, 1, 0, dir == dir_client_to_server);
     42 	// msg ("Got character %c (%d) while scanning chunk size", *cp, *cp);
     43 	net_write (dest, cp, 1, dir == dir_client_to_server);
     44 	if (*cp == '\n') {
     45 	    sscanf (hexbuf, "%x", &ret);
     46 	    free (hexbuf);
     47 	    // msg ("Got chunk size 0x%x (%d)", ret, ret);
     48 	    return (ret);
     49 	}
     50 	if (in_number) {
     51 	    if (is_hex_digit (*cp))
     52 		hexbuf = xstrcatch (hexbuf, *cp);
     53 	    else
     54 		in_number = 0;
     55 	}
     56     }
     57 }
     58 
     59 void http_copy (HttpHeader *h, int src, int dst, CopyDirection dir) {
     60     unsigned char const *mode;
     61     unsigned nbytes;
     62     
     63     msg ("Service %s: copying HTTP body from %s",
     64 	 activeservice->name,
     65 	 dir == dir_client_to_server ?
     66 	   "client to server" : "server to client");
     67 
     68     /* Check in what 'mode' we are.
     69      * We know 3 modes:
     70      * - Transfer-Encoding is chunked: we copy chunks
     71      * - Content-Length is supplied: we copy that # of bytes
     72      * - None of the above: don't do anything, http_serve() will go
     73      *   into copy-thru mode
     74      */
     75   
     76     if ( (mode = http_header_val (h, "transfer-encoding")) && *mode ) {
     77 	if (strncasecmp ( (char const *) mode, "chunked", 7))
     78 	    error ("Service %s: can't handle transfer-encoding '%s'",
     79 		   activeservice->name, mode);
     80 	msg ("Service %s: copying chunks from %s",
     81 	     activeservice->name, dir == dir_client_to_server ?
     82 	         "client to server" : "server to client");
     83 	while (1) {
     84 	    /* See how large the chunk will be. */
     85 	    nbytes = getchunk (src, dst, dir);
     86 	    msg ("Service %s: Next chunk is 0x%x (%d) bytes",
     87 		 activeservice->name, nbytes, nbytes);
     88 	    /* Copy the chunk. Add 2 bytes for the \r\n that follows. */
     89 	    copy (src, dst, dir, nbytes + 2);
     90 	    /* Last chunksize of 0 signals the end. */
     91 	    if (!nbytes)
     92 		break;
     93 	}
     94     } else if ( (mode = http_header_val (h, "content-length")) &&
     95 		mode ) {
     96 	nbytes = atoi ( (char const *) mode );
     97 	msg ("Service %s: copying %u bytes of content from %s",
     98 	     activeservice->name, nbytes, 
     99 	     dir == dir_client_to_server ?
    100 	         "client to server" : "server to client");
    101 	copy (src, dst, dir, nbytes);
    102     } else
    103 	msg ("Service %s: no body to send", activeservice->name);
    104 }