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 }