httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject Re: [PATCH] multipart/byteranges + keepalive
Date Mon, 10 Feb 1997 02:55:50 GMT
I notice that with or without this patch, apache dumps an extra crlf pair
after the response header and before the first range (when doing
multipart/byteranges).  But the example in section 19.2 of rfc2068 doesn't
have that extra crlf... are we compliant? 

At any rate I give this a +1 assuming that if we aren't compliant you'll
provide a tweak.

Dean

P.S. gcc's optimizer won't optimize the tail recursion in
internal_byterange()... not that it's really important considering it's
only triggered by errors in the client's request. 

On Sun, 9 Feb 1997, Alexei Kosut wrote:

> A thought crossed my head earlier today: after the incident this week
> with Netscape and byteranges, I've decided I no longer trust
> developers to implement specs like HTTP/1.1 correctly (heck, we try
> really hard, and we don't always get it right). So where possible, we
> should make Apache try to avoid breaking clients that might not
> implement HTTP/1.1 to the letter. In other words, don't rely on the
> fine print in the spec, even if it has a MUST for the client end.
> 
> One obscure part of HTTP/1.1 that Apache current obeys is that there
> are three ways (at least) to make a connection persistent: it can have
> a Content-Length header, it can use chunked transfer-coding, or it
> can be a multipart/byteranges response (because you can determine
> easily the end of a multipart MIME document).
> 
> I now believe that when (if) some clients implement HTTP/1.1, they will
> "forget" about that last one. However, the current Apache will open a
> persistent connection that way. This will result in problematic
> behavior.
> 
> So enclosed is a patch that does the obvous thing; it adds a
> Content-Length header to multipart/byteranges responses. This has been
> tested with Netscape Navigator 3.01, and works fine.
> 
> This patch also has the added benefit that the browser can now give
> you a percentage done when receiving the file, since it has a total
> content length to compare against. When downloading large PDF files,
> for example (since PDF seems to be what 99.9% of the byteserved
> files are nowadays), getting a percentage done instead of just how
> many bytes received is nice.
> 
> Anyhow, this is for inclusion in 1.2b7. Someone please test and make
> sure my addition is correct; I tested it a bit, and it seems to be
> right, but... Note that I say things like "4 + x + 4", not "8 + x", so
> it's more obvious what I'm doing. Compilers should optimize that for
> me, right?
> 
> Index: http_protocol.c
> ===================================================================
> RCS file: /export/home/cvs/apache/src/http_protocol.c,v
> retrieving revision 1.98
> diff -c -r1.98 http_protocol.c
> *** http_protocol.c	1997/02/06 21:40:35	1.98
> --- http_protocol.c	1997/02/09 08:00:53
> ***************
> *** 106,111 ****
> --- 106,113 ----
>       return 1;
>   }
>   
> + static int internal_byterange(int, int*, request_rec*, char**, long*, long*);
> + 
>   int set_byterange (request_rec *r)
>   {
>       char *range = table_get (r->headers_in, "Range");
> ***************
> *** 161,171 ****
>       else {
>   	/* a multiple range */
>   	char boundary[33];	/* Long enough */
>   	
>   	r->byterange = 2;
> - 	table_unset(r->headers_out, "Content-Length");
>   	ap_snprintf(boundary, sizeof(boundary), "%lx%lx", r->request_time, (long)getpid());
>   	r->boundary = pstrdup(r->pool, boundary);
>       }
>       
>       r->status = PARTIAL_CONTENT;
> --- 163,177 ----
>       else {
>   	/* a multiple range */
>   	char boundary[33];	/* Long enough */
> + 	char *r_range = pstrdup(r->pool, range + 6);
> + 	int tlength = 0;
>   	
>   	r->byterange = 2;
>   	ap_snprintf(boundary, sizeof(boundary), "%lx%lx", r->request_time, (long)getpid());
>   	r->boundary = pstrdup(r->pool, boundary);
> + 	while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL));
> + 	ap_snprintf(ts, sizeof(ts), "%ld", tlength);
> + 	table_set(r->headers_out, "Content-Length", ts);
>       }
>       
>       r->status = PARTIAL_CONTENT;
> ***************
> *** 175,205 ****
>   }
>   
>   int each_byterange (request_rec *r, long *offset, long *length) {
>       long range_start, range_end;
>       char *range;
>   
> !     if (!*r->range) {
> ! 	if (r->byterange > 1)
> ! 	    rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL);
>   	return 0;
>       }
>   
> !     range = getword_nc(r->pool, &r->range, ',');
>       if (!parse_byterange(range, r->clength, &range_start, &range_end))
> ! 	return each_byterange(r, offset, length);	/* Skip this one */
>   
>       if (r->byterange > 1) {
>   	char *ct = r->content_type ? r->content_type : default_type(r);
>   	char ts[MAX_STRING_LEN];
> ! 
>   	ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end, r->clength);
> ! 	rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ",
>   	       ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012",
>   	       NULL);
>       }
>   
> !     *offset = range_start;
> !     *length = range_end - range_start + 1;
>       return 1;
>   }
>   
> --- 181,243 ----
>   }
>   
>   int each_byterange (request_rec *r, long *offset, long *length) {
> +     return internal_byterange(1, NULL, r, &r->range, offset, length);
> + }
> + 
> + /* If this function is called with realreq=1, it will spit out
> +  * the correct headers for a byterange chunk, and set offset and
> +  * length to the positions they should be.
> +  *
> +  * If it is called with realreq=0, it will add to tlength the length
> +  * it *would* have used had it been called with 1.
> +  *
> +  * Either case will return 1 if it should be called again, and 0
> +  * when done.
> +  *
> +  */
> + 
> + static int internal_byterange(int realreq, int *tlength, request_rec *r,
> + 			      char **r_range, long *offset, long *length) {
>       long range_start, range_end;
>       char *range;
>   
> !     if (!**r_range) {
> ! 	if (r->byterange > 1) {
> ! 	    if (realreq)
> ! 		rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL);
> ! 	    else
> ! 		*tlength += 4 + strlen(r->boundary) + 4;
> ! 	}
>   	return 0;
>       }
>   
> !     range = getword_nc(r->pool, r_range, ',');
>       if (!parse_byterange(range, r->clength, &range_start, &range_end))
> ! 	/* Skip this one */
> ! 	return internal_byterange(realreq, tlength, r, r_range, offset,
> ! 				  length);
>   
>       if (r->byterange > 1) {
>   	char *ct = r->content_type ? r->content_type : default_type(r);
>   	char ts[MAX_STRING_LEN];
> ! 	
>   	ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end, r->clength);
> ! 	if (realreq)
> ! 	    rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ",
>   	       ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012",
>   	       NULL);
> + 	else
> + 	    *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
> + 		strlen(ts) + 4;
>       }
>   
> !     if (realreq) {
> ! 	*offset = range_start;
> ! 	*length = range_end - range_start + 1;
> !     }
> !     else {
> ! 	*tlength += range_end - range_start + 1;
> !     }
>       return 1;
>   }
>   
> ***************
> *** 228,234 ****
>   	(r->server->keep_alive_max > r->connection->keepalives)) &&
>   	(r->server->keep_alive_timeout > 0) &&
>   	(r->status == USE_LOCAL_COPY || r->header_only || length || tenc ||
> ! 	 ((r->proto_num >= 1001) && (r->byterange > 1 || (r->chunked
= 1)))) &&
>   	(!find_token(r->pool, conn, "close")) &&
>   	((ka_sent = find_token(r->pool, conn, "keep-alive")) ||
>   	 r->proto_num >= 1001)) {
> --- 266,272 ----
>   	(r->server->keep_alive_max > r->connection->keepalives)) &&
>   	(r->server->keep_alive_timeout > 0) &&
>   	(r->status == USE_LOCAL_COPY || r->header_only || length || tenc ||
> ! 	 ((r->proto_num >= 1001) && (r->chunked = 1))) &&
>   	(!find_token(r->pool, conn, "close")) &&
>   	((ka_sent = find_token(r->pool, conn, "keep-alive")) ||
>   	 r->proto_num >= 1001)) {
> 
> 
> -- 
> ________________________________________________________________________
> Alexei Kosut <akosut@nueva.pvt.k12.ca.us>      The Apache HTTP Server
> URL: http://www.nueva.pvt.k12.ca.us/~akosut/   http://www.apache.org/
> 
> 


Mime
View raw message