new Curl_ConnectHTTPProxyTunnel() function, needs a **lot** of testing!!!
authorDaniel Stenberg <daniel@haxx.se>
Mon, 12 Nov 2001 09:47:09 +0000 (09:47 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 12 Nov 2001 09:47:09 +0000 (09:47 +0000)
lib/http.c

index 9526e51..2fe8e08 100644 (file)
@@ -205,28 +205,6 @@ CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
 /* ------------------------------------------------------------------------- */
 
 /*
- * Read everything until a newline.
- */
-
-static
-int GetLine(int sockfd, char *ptr, struct connectdata *conn)
-{
-  ssize_t nread;
-
-  /* get us a full line, terminated with a newline */
-  for(nread=0; (nread<BUFSIZE); nread++, ptr++) {
-    if((CURLE_OK != Curl_read(conn, sockfd, ptr, 1, &nread)) ||
-       (nread <= 0) || (*ptr == '\n'))
-      break;
-  }
-  *ptr=0; /* zero terminate */
-  
-  return nread>0?nread:0;
-}
-
-
-
-/*
  * This function checks the linked list of custom HTTP headers for a particular
  * header (prefix).
  */
@@ -258,6 +236,22 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
   struct SessionHandle *data=conn->data;
   CURLcode result;
 
+  int nread;   /* total size read */
+  int perline; /* count bytes per line */
+  bool keepon=TRUE;
+  ssize_t gotbytes;
+  char *ptr;
+  int timeout = 3600; /* default timeout in seconds */
+  struct timeval interval;
+  fd_set rkeepfd;
+  fd_set readfd;
+  char *line_start;
+
+#define SELECT_OK      0
+#define SELECT_ERROR   1
+#define SELECT_TIMEOUT 2
+  int error = SELECT_OK;
+
   infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
 
   /* OK, now send the connect request to the proxy */
@@ -276,19 +270,105 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
     return result;
   }
 
-  /* wait for the proxy to send us a HTTP/1.0 200 OK header */
-  while(GetLine(tunnelsocket, data->state.buffer, conn)) {
-    if('\r' == data->state.buffer[0])
-      break; /* end of headers */
-    if(data->set.verbose)
-      fprintf(data->set.err, "< %s\n", data->state.buffer);
-
-    if(2 == sscanf(data->state.buffer, "HTTP/1.%d %d",
-                   &subversion,
-                   &httperror)) {
-      ;
+  /* Now, read the full reply we get from the proxy */
+
+
+  if(data->set.timeout) {
+    /* if timeout is requested, find out how much remaining time we have */
+    timeout = data->set.timeout - /* timeout time */
+      Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
+    if(timeout <=0 ) {
+      failf(data, "Transfer aborted due to timeout");
+      return -SELECT_TIMEOUT; /* already too little time */
     }
   }
+
+  FD_ZERO (&readfd);           /* clear it */
+  FD_SET (tunnelsocket, &readfd);     /* read socket */
+
+  /* get this in a backup variable to be able to restore it on each lap in the
+     select() loop */
+  rkeepfd = readfd;
+
+  ptr=data->state.buffer;
+  line_start = ptr;
+
+  nread=0;
+  perline=0;
+  keepon=TRUE;
+
+  while((nread<BUFSIZE) && (keepon && !error)) {
+    readfd = rkeepfd;             /* set every lap */
+    interval.tv_sec = timeout;
+    interval.tv_usec = 0;
+
+    switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
+    case -1: /* select() error, stop reading */
+      error = SELECT_ERROR;
+      failf(data, "Transfer aborted due to select() error");
+      break;
+    case 0: /* timeout */
+      error = SELECT_TIMEOUT;
+      failf(data, "Transfer aborted due to timeout");
+      break;
+    default:
+      /*
+       * This code previously didn't use the kerberos sec_read() code
+       * to read, but when we use Curl_read() it may do so. Do confirm
+       * that this is still ok and then remove this comment!
+       */
+      if(CURLE_OK != Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
+                               &gotbytes))
+        keepon = FALSE;
+      else if(gotbytes <= 0) {
+        keepon = FALSE;
+        error = SELECT_ERROR;
+        failf(data, "Connection aborted");
+      }
+      else {
+        /* we got a whole chunk of data, which can be anything from one
+         * byte to a set of lines and possibly just a piece of the last
+         * line */
+        int i;
+
+        nread += gotbytes;
+        for(i = 0; i < gotbytes; ptr++, i++) {
+          perline++; /* amount of bytes in this line so far */
+          if(*ptr=='\n') {
+            /* a newline is CRLF in ftp-talk, so the CR is ignored as
+               the line isn't really terminated until the LF comes */
+
+            /* output debug output if that is requested */
+            if(data->set.verbose) {
+              fputs("< ", data->set.err);
+              fwrite(line_start, perline, 1, data->set.err);
+              /* no need to output LF here, it is part of the data */
+            }
+            
+            if('\r' == line_start[0]) {
+              /* end of headers */
+              keepon=FALSE;
+              break; /* breaks out of loop, not switch */
+            }
+
+            if(2 == sscanf(line_start, "HTTP/1.%d %d",
+                           &subversion,
+                           &httperror)) {
+              ;
+            }
+
+            perline=0; /* line starts over here */
+            line_start = ptr+1;
+          }
+        }
+      }
+      break;
+    } /* switch */
+  } /* while there's buffer left and loop is requested */
+
+  if(error)
+    return CURLE_READ_ERROR;
+
   if(200 != httperror) {
     if(407 == httperror)
       /* Added Nov 6 1998 */