/***************************************************************************
 *
 * Copyright (c) 2000 BalaBit IT Ltd, Budapest, Hungary
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: httpfltr.c,v 1.19.4.1 2001/05/11 14:19:11 bazsi Exp $
 *
 * Author: Balazs Scheidler <bazsi@balabit.hu>
 * Auditor: 
 * Last audited version: 
 * Notes:
 *   Based on the code by: Viktor Peter Kovacs <vps__@freemail.hu>
 *
 ***************************************************************************/
 
#include "http.h"

#include <zorp/log.h>

gboolean
http_transfer_filter_copy(HttpProxy *self, int from, int to, gint content_length)
{
  gchar buf[HTTP_BLOCKSIZE];
  guint bytes;

  z_proxy_enter(self);  
  if ((from ^ to) != 1)
    {
      z_proxy_leave(self);
      return FALSE;
    }
  while (content_length == -1 || content_length > 0)
    {
      bytes = MIN(sizeof(buf), content_length);
      if (!http_read(self, from, buf, bytes, &bytes))
        {
          z_proxy_leave(self);
          return FALSE;
        }
        
      if (bytes == 0)
        break;
      
      if (!http_write(self, to, buf, bytes))
        {
          z_proxy_leave(self);
          return FALSE;
        }
      if (content_length != -1)
        content_length -= bytes;
    }
  z_proxy_leave(self);
  return TRUE;
}

gboolean
http_transfer_filter_chunked(HttpProxy *self, int from, int to, gint content_length)
{
  gchar buf[32];
  
  /* NOTE: we strip off extra data from the end of the block size, ie:
     HTTP permits using the following format:
     
       0020; eof
     
     where eof is the extradata, we strip this off, since we have no way
     verifying it. */
  z_proxy_enter(self);

  if ((from ^ to) != 1)
    {
      z_proxy_leave(self);
      return FALSE;
    }

  while (1)
    {
      gchar *line;
      guint line_length, res, content_length;
      
      res = z_read_line_get(self->readline[from], &line, &line_length);
      if (ST_ERROR(res) != ST_OK)
        {
          z_proxy_leave(self);
          return FALSE;
        }
        
      {
        gchar *end;
              
        if (line_length > sizeof(buf) - 3)
          {
            z_proxy_leave(self);
            return FALSE;
          }
        strncpy(buf, line, line_length);
        buf[line_length] = 0;
        content_length = strtoul(buf, &end, 16);
        if (end == buf)
          {
            /* no characters processed */
            z_proxy_leave(self);
            return FALSE;
          }
        else
          line_length = end - buf;
        buf[line_length] = '\r';
        buf[line_length + 1] = '\n';
        buf[line_length + 2] = 0;
      }
      
      /* send block size */
      if (!http_write(self, to, buf, line_length + 2))
        {
          z_proxy_leave(self);
          return FALSE;
        }

      if (content_length != 0)
        {
          /* copy block */
          if (!http_transfer_filter_copy(self, from, to, content_length))
            {
              z_proxy_leave(self);
              return FALSE;
            }
        }

      res = z_read_line_get(self->readline[from], &line, &line_length);
      if (ST_ERROR(res) != ST_OK || line_length != 0)
        {
          z_proxy_leave(self);
          return FALSE;
        }

      strcpy(buf, "\r\n");
      if (!http_write(self, to, buf, 2))
        {
          z_proxy_leave(self);
          return FALSE;
        }
      if (content_length == 0)
        break;
    }
  z_proxy_leave(self);
  return TRUE;
}

