Re: reply body modification

From: Michael Ulbrich <mul@dont-contact.us>
Date: Sat, 06 May 2006 16:35:00 +0200

Adrian Chadd wrote:
> Could you share the patch?
>
>
>
> adrian

Hi Adrian,

thanks for your quick reply!

Yes, of course, you will find the patch attached to this message. I
deleted the lines which actually modify the JPEG body.

Basically data from buf is copied to mod_buf and modified there. Sizes
and the Content-Length header field are updated in accordance to the
amount of inserted data. Towards the end buf and size take over the
modified values and normal clientSendMoreData() processing continues.

If modifications have been done, care is taken that http->out.offset is
  incremented only by old_body_size. Otherwise the followup data on the
next call to clientSendMoreData() will be out of sync.

I had to modify one line in clientWriteComplete(), otherwise the call to
clientWriteComplete(fd, NULL, 0, 0, http); with size = 0 was interpreted
as "transfer DONE".

With CLIENT_SOCK_SZ set to 16k this code works ok. Problems arise when
increasing this value to 32k, as I wrote in my earlier message.

Please apologize the somewhat crude hack, but it was meant as a first
test, whether something like that could be done at all.

Thanks again and best regards ... Michael

--- src/client_side.c.orig 2006-05-03 16:19:57.491424980 +0200
+++ src/client_side.c 2006-05-03 16:48:03.920598576 +0200
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "libiptc/iptc.h"
 
 #if IPF_TRANSPARENT
 #if HAVE_SYS_IOCTL_H
@@ -101,7 +102,10 @@
 #endif
 
 static const char *const crlf = "\r\n";
+extern int errno;
 
+#define JPEG_MOD 1
+#define BUFSIZE 16384
 #define FAILURE_MODE_TIME 300
 
 /* Local functions */
@@ -1968,6 +1972,32 @@
     squid_off_t body_size = size;
     MemBuf mb;
     squid_off_t check_size = 0;
+
+ int i = 0, j = 0, ret = 0, done = 0;
+ int APP13_len = 0, BIM_num = 0;
+ FILE * bin_in_fd = NULL;
+ FILE * txt_in_fd = NULL;
+ FILE * txt_out_fd = NULL;
+ FILE * bin_out_fd = NULL;
+ FILE * jpg_out_fd = NULL;
+ unsigned int marker;
+ unsigned char iptc_line[BUFSIZE];
+ unsigned char tag_text[BUFSIZE];
+ int iptc = 0, recno = 0, spec = 0;
+ long iptc_bin_len = 0;
+ long iptc_bin_elen = 0;
+ long content_length = 0;
+ long diff_hdr_size = 0;
+ long diff_body_size = 0;
+ char *mod_buf = NULL;
+ char *mod_body_buf = NULL;
+ char new_clength[10];
+ char tag_time[13];
+ char *client_ip;
+ squid_off_t mod_size = 0, mod_body_size = 0;
+ squid_off_t old_body_size = 0, old_hdr_size = 0;
+ int mod_flag = 0;
+
     debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size);
     assert(size <= CLIENT_SOCK_SZ);
     assert(http->request != NULL);
@@ -2000,6 +2030,289 @@
         memFree(buf, MEM_CLIENT_SOCK_BUF);
         return;
     }
+
+ if (JPEG_MOD && http->out.offset == 0) {
+ rep = clientBuildReply(http, buf, size);
+ if(rep) {
+ if(rep->content_type.buf != NULL) {
+ debug(33, 2) ("clientSendMoreData: Reply content-type is : %s\n", rep->content_type.buf);
+ if(strncmp(rep->content_type.buf, "image/jpeg", 10) == 0) {
+ debug(33, 2) ("clientSendMoreData: Reply content-type is JPEG\n");
+ debug(33, 2) ("clientSendMoreData: Reply content-length is: %ld\n", (long)rep->content_length);
+ if(rep->content_length == -1 || rep->content_length > 25000) {
+ debug(33, 2) ("clientSendMoreData: Reply content-length unknown or > 25000\n");
+ if(size < CLIENT_SOCK_SZ) {
+ if(rep->content_length == -1) {
+ debug(33, 2) ("clientSendMoreData: JPEG with unknown Content-Length: Checking buf for EOI\n");
+ debug(33, 2) ("clientSendMoreData: buf[size - 2]: %02x\n", (unsigned char)buf[(int)size - 2]);
+ debug(33, 2) ("clientSendMoreData: buf[size - 1]: %02x\n", (unsigned char)buf[(int)size - 1]);
+ if((unsigned char)buf[(int)size - 2] != 0xff || (unsigned char)buf[(int)size - 1] != 0xd9) { /* No EOI Marker. Wait for more ... */
+ clientWriteComplete(fd, NULL, 0, 0, http);
+ memFree(buf, MEM_CLIENT_SOCK_BUF);
+ httpReplyDestroy(rep);
+ return;
+ } else {
+ /* image is too small (completely fits in buf of size CLIENT_SOCK_SZ)
+ break out of JPEG_MOD block and continue with normal reply processing */
+ debug(33, 2) ("clientSendMoreData: small JPEG image found: %d\n", size - rep->hdr_sz);
+ }
+ } else {
+ clientWriteComplete(fd, NULL, 0, 0, http);
+ memFree(buf, MEM_CLIENT_SOCK_BUF);
+ httpReplyDestroy(rep);
+ return;
+ }
+ } else {
+ content_length = rep->content_length;
+ old_hdr_size = rep->hdr_sz;
+ old_body_size = size - old_hdr_size;
+ body_buf = buf + old_hdr_size;
+ bin_in_fd = tmpfile();
+ txt_in_fd = tmpfile();
+ txt_out_fd = tmpfile();
+ bin_out_fd = tmpfile();
+ jpg_out_fd = tmpfile();
+ ret = fwrite(body_buf, (size_t)1, (size_t)old_body_size, bin_in_fd);
+ debug(33, 2) ("clientSendMoreData: %d of %ld bytes written to bin_in_fd\n", ret, (long)old_body_size);

<SNIPPED JPEG body modifications>

+
+ mod_buf = memAllocate(MEM_32K_BUF); /* Buffer to hold modified client reply */
+ if(mod_buf == NULL)
+ debug(33, 2) ("clientSendMoreData: memAllocate error: %d\n", errno);
+
+ if(content_length != -1) {
+ /* Modify "Content-Length:" */
+ char *cl_pos = strstr(buf, "Content-Length: ");
+ i = 0;
+ while(*(cl_pos + i) != ' ') {
+// debug(33, 2) ("clientSendMoreData: %c\n", *(cl_pos + i));
+ i++;
+ }
+ i++; /* Skip SPC */
+ j = 0;
+ while(*(cl_pos + i + j) != '\r') {
+// debug(33, 2) ("clientSendMoreData: %c\n", *(cl_pos + i + j));
+ j++;
+ }
+ debug(33, 2) ("clientSendMoreData: i = %d, j = %d\n", i, j);
+
+ int length = (int)cl_pos + i - (int)buf;
+ debug(33, 2) ("clientSendMoreData: length: %d\n", length);
+ memcpy(mod_buf, buf, length); /* Copy hdr up to and including "Content-Length: " */
+ snprintf(new_clength, 10, "%d", (int)content_length + (int)diff_body_size);
+ int k = strlen(new_clength);
+ diff_hdr_size = k - j;
+ debug(33, 2) ("clientSendMoreData: new_clength: %s, diff_hdr_size: %ld\n", new_clength, diff_hdr_size);
+ snprintf(mod_buf + length, k + 1, "%s", new_clength); /* Insert value */
+ memcpy(mod_buf + length + k, buf + length + j, rep->hdr_sz - length - j); /* Copy rest of header */
+ } else {
+ /* Copy HTTP reply header without modification */
+ memcpy(mod_buf, buf, rep->hdr_sz);
+ }
+
+ mod_size = size + diff_hdr_size + diff_body_size;
+ mod_body_size = mod_size - rep->hdr_sz + diff_hdr_size;
+ mod_body_buf = mod_buf + rep->hdr_sz + diff_hdr_size;
+ ret = fread(mod_body_buf, 1, mod_body_size, jpg_out_fd);
+ if(ret != mod_body_size) {
+ debug(33, 2) ("clientSendMoreData: JPEG length error: expected %ld, got %d\n", (long)mod_body_size, ret);
+ if(mod_body_size - ret == 1) { /* One byte missing: jpegembed swallowed 0xff */
+ debug(33, 2) ("clientSendMoreData: last byte in buf: %02x\n", (unsigned char)buf[size - 1]);
+ debug(33, 2) ("clientSendMoreData: Appending 0xff to mod_buf\n");
+ mod_buf[mod_size - 1] = 0xff;
+ }
+ }
+
+ memFree(buf, MEM_CLIENT_SOCK_BUF); /* CLIENT_SOCK_SZ = 16k */
+ buf = mod_buf; /* MEM_32K_BUF */
+ size = mod_size;
+ mod_flag = 1;
+
+ fclose(bin_in_fd);
+ fclose(txt_in_fd);
+ fclose(txt_out_fd);
+ fclose(bin_out_fd);
+ fclose(jpg_out_fd);
+ }
+ }
+ }
+ httpReplyDestroy(rep);
+ }
+ }
+ }
     if (http->out.offset == 0) {
         rep = clientBuildReply(http, buf, size);
         if (rep) {
@@ -2071,6 +2384,11 @@
         /* Avoid copying to MemBuf for non-range requests */
         /* Note, if we're here, then 'rep' is known to be NULL */
         http->out.offset += body_size;
+
+// for (i = 0; i < 8; i++) {
+// debug(33, 5) ("BODY: %02x\n", (unsigned char)*(buf + i));
+// }
+
         comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL);
         /* NULL because clientWriteBodyComplete frees it */
         return;
@@ -2121,16 +2439,29 @@
         if (!clientPackMoreRanges(http, body_buf, body_size, &mb))
             http->flags.done_copying = 1;
     } else if (body_buf && body_size) {
- http->out.offset += body_size;
+
+// for (i = 0; i < 8; i++) {
+// debug(33, 5) ("BODY: %02x\n", (unsigned char)*(body_buf + i));
+// }
+ if(mod_flag)
+ http->out.offset += old_body_size;
+ else
+ http->out.offset += body_size;
         check_size += body_size;
         memBufAppend(&mb, body_buf, body_size);
     }
     if (!http->request->range && http->request->method == METHOD_GET)
         assert(check_size == size);
+
+debug(33, 5) ("body_size: %d memBuf size: %d\n", (int)body_size, mb.size);
+
     /* write */
     comm_write_mbuf(fd, mb, clientWriteComplete, http);
     /* if we don't do it, who will? */
- memFree(buf, MEM_CLIENT_SOCK_BUF);
+ if(mod_flag)
+ memFree(buf, MEM_32K_BUF);
+ else
+ memFree(buf, MEM_CLIENT_SOCK_BUF);
 }
 
 /*
@@ -2248,7 +2579,7 @@
         comm_close(fd); /* yuk */
     } else if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
         comm_close(fd);
- } else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) {
+ } else if ((done = clientCheckTransferDone(http)) != 0 && size == 0) {
         debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd);
         /* We're finished case */
         if (httpReplyBodySize(http->request->method, entry->mem_obj->reply) < 0) {
Received on Sat May 06 2006 - 08:51:51 MDT

This archive was generated by hypermail pre-2.1.9 : Thu Jun 01 2006 - 12:00:04 MDT