# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: atcs.matthew@gmail.com-20091106225203-4i1s6bhkpd0nd4rp
# target_branch: file:///home/lytithwyn/squid-repo/trunk/
# testament_sha1: a76d3bba71e0948160b4218656b1a9927e005128
# timestamp: 2009-11-06 17:53:57 -0500
# base_revision_id: kinkie@squid-cache.org-20091106162216-\
#   ucnpf7lk1ane5rhw
# 
# Begin patch
=== modified file 'src/HttpHdrRange.cc'
--- src/HttpHdrRange.cc	2009-01-31 17:23:17 +0000
+++ src/HttpHdrRange.cc	2009-10-13 21:10:05 +0000
@@ -530,17 +530,17 @@
  * grabbing the needed range elements from the origin.
  */
 bool
-HttpHdrRange::offsetLimitExceeded() const
+HttpHdrRange::offsetLimitExceeded(int64_t limit) const
 {
     if (NULL == this)
         /* not a range request */
         return false;
 
-    if (Config.rangeOffsetLimit == 0)
+    if (limit == 0)
         /* disabled */
         return true;
 
-    if (-1 == Config.rangeOffsetLimit)
+    if (-1 == limit)
         /* forced */
         return false;
 
@@ -548,7 +548,7 @@
         /* tail request */
         return true;
 
-    if (Config.rangeOffsetLimit >= firstOffset())
+    if (limit >= firstOffset())
         /* below the limit */
         return false;
 

=== modified file 'src/HttpHeaderRange.h'
--- src/HttpHeaderRange.h	2009-03-31 12:39:30 +0000
+++ src/HttpHeaderRange.h	2009-10-13 21:10:05 +0000
@@ -103,7 +103,7 @@
     bool willBeComplex() const;
     int64_t firstOffset() const;
     int64_t lowestOffset(int64_t) const;
-    bool offsetLimitExceeded() const;
+    bool offsetLimitExceeded(int64_t) const;
     bool contains(HttpHdrRangeSpec& r) const;
     Vector<HttpHdrRangeSpec *> specs;
 

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2009-11-06 11:58:03 +0000
+++ src/Makefile.am	2009-11-06 22:52:03 +0000
@@ -403,6 +403,8 @@
 	PeerSelectState.h \
 	PingData.h \
 	protos.h \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
@@ -1162,6 +1164,8 @@
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
@@ -1337,6 +1341,8 @@
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
@@ -1486,6 +1492,8 @@
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
@@ -1625,6 +1633,8 @@
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	pconn.cc \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
@@ -1778,6 +1788,8 @@
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \
@@ -1873,6 +1885,8 @@
 	HttpHdrScTarget.cc url.cc \
 	StatHist.cc HttpHdrRange.cc ETag.cc tests/stub_errorpage.cc \
 	tests/stub_HttpRequest.cc tests/stub_access_log.cc \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	refresh.cc \
 	tests/stub_store_client.cc \
 	tests/stub_tools.cc \
@@ -2137,6 +2151,8 @@
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
+	rangeOffsetLimit.h \
+	rangeOffsetLimit.cc \
 	redirect.cc \
 	referer.cc \
 	refresh.cc \

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2009-10-31 11:53:09 +0000
+++ src/cache_cf.cc	2009-11-04 17:42:37 +0000
@@ -121,6 +121,7 @@
 static void update_maxobjsize(void);
 static void configDoConfigure(void);
 static void parse_refreshpattern(refresh_t **);
+static void parse_rangeoffsetlimit(range_offset_t **);
 static int parseTimeUnits(const char *unit);
 static void parseTimeLine(time_t * tptr, const char *units);
 static void parse_ushort(u_short * var);
@@ -2448,6 +2449,90 @@
 }
 
 static void
+dump_rangeoffsetlimit(StoreEntry * entry, const char *name, range_offset_t * head)
+{
+    while (head != NULL) {
+	storeAppendPrintf(entry, "%s %d %s %s\n",
+	    name,
+	    (int)head->limit,
+	    head->flags.icase ? " -i" : null_string,
+	    head->pattern);
+	storeAppendPrintf(entry, "\n");
+	head = head->next;
+    }
+}
+
+static void
+parse_rangeoffsetlimit(range_offset_t ** head)
+{
+    char *token;
+    int64_t offset;
+    char *pattern = xstrdup(".*");;
+
+    range_offset_t *t;
+    regex_t comp;
+    int errcode;
+    int flags = REG_EXTENDED | REG_NOSUB;
+    int gotPattern = 0;
+
+    offset = (int64_t) GetInteger();
+
+    if((token = strtok(NULL, w_space)) != NULL) {
+        if (strcmp(token, "-i") == 0) {
+            flags |= REG_ICASE;
+        } else if (strcmp(token, "+i") == 0) {
+            flags &= ~REG_ICASE;
+        } else {
+        	safe_free(pattern);
+        	pattern = xstrdup(token);
+        	gotPattern = 1;
+        }
+    }
+
+    if(((token = strtok(NULL, w_space)) != NULL) && !gotPattern) {
+    	safe_free(pattern);
+    	pattern = xstrdup(token);
+    	gotPattern = 1;
+    } else if((token != NULL) && gotPattern) {
+        debugs(22, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
+        debugs(22, 0, "parse_rangeoffsetlimit: extra parameter '" << token);
+    }
+
+    if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
+        char errbuf[256];
+        regerror(errcode, &comp, errbuf, sizeof errbuf);
+        debugs(22, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
+        debugs(22, 0, "parse_rangeoffsetlimit: Invalid regular expression '" << pattern << "': " << errbuf);
+        return;
+    }
+
+    t = (range_offset_t*)xcalloc(1, sizeof(range_offset_t));
+    t->pattern = (char *) xstrdup(pattern);
+    t->compiled_pattern = comp;
+    t->limit = offset;
+    if (flags & REG_ICASE)
+        t->flags.icase = 1;
+
+    t->next = NULL;
+    while (*head)
+        head = &(*head)->next;
+    *head = t;
+    safe_free(pattern);
+}
+
+static void
+free_rangeoffsetlimit(range_offset_t ** head)
+{
+	range_offset_t *t;
+    while ((t = *head) != NULL) {
+	*head = t->next;
+	safe_free(t->pattern);
+	regfree(&t->compiled_pattern);
+	safe_free(t);
+    }
+}
+
+static void
 dump_string(StoreEntry * entry, const char *name, char *var)
 {
     if (var != NULL)

=== modified file 'src/cf.data.depend'
--- src/cf.data.depend	2009-08-04 02:07:56 +0000
+++ src/cf.data.depend	2009-10-13 21:10:05 +0000
@@ -42,6 +42,7 @@
 peer_access		cache_peer acl
 QosConfig
 refreshpattern
+rangeoffsetlimit
 removalpolicy
 size_t
 IpAddress_list

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2009-11-06 11:58:03 +0000
+++ src/cf.data.pre	2009-11-06 22:52:03 +0000
@@ -3442,28 +3442,48 @@
 DOC_END
 
 NAME: range_offset_limit
-COMMENT: (bytes)
-TYPE: b_int64_t
+COMMENT: (bytes) [-i] [pattern]
+TYPE: rangeoffsetlimit
 LOC: Config.rangeOffsetLimit
 DEFAULT: 0 KB
 DOC_START
-	Sets a upper limit on how far into the the file a Range request
-	may be to cause Squid to prefetch the whole file. If beyond this
-	limit Squid forwards the Range request as it is and the result
-	is NOT cached.
+	usage: (bytes) [-i] [pattern]
+	
+	Sets a upper limit on how far (number of bytes) into the the file 
+	a Range request	may be to cause Squid to prefetch the whole file. 
+	If beyond this limit Squid forwards the Range request as it is and 
+	the result is NOT cached.
 
 	This is to stop a far ahead range request (lets say start at 17MB)
 	from making Squid fetch the whole object up to that point before
 	sending anything to the client.
-
-	A value of 0 causes Squid to never fetch more than the
+	
+	Multiple range_offset_limit lines may be specified, and they will 
+	be searched from top to bottom on each request until a match is found. 
+	The first match found will be used.  If no line matches a request, the 
+	default limit of 0 bytes will be used.
+	
+	'bytes' is the limit specified as a number of bytes.
+	
+	A byte value of 0 causes Squid to never fetch more than the
 	client requested. (default)
 
-	A value of -1 causes Squid to always fetch the object from the
+	A byte value of -1 causes Squid to always fetch the object from the
 	beginning so it may cache the result. (2.0 style)
+	
+	NP: Using -1 as the byte value here will override any quick_abort settings 
+		that may otherwise apply to the range request. The range request will
+	    be fully fetched from start to finish regardless of the client
+	    actions. This affects bandwidth usage.
+	
+	'-i' is an optional modifier to make the pattern case insensitive.
+	
+	'pattern' is an optional parameter that will cause the limit to be 
+	applied only to requests where the url matches pattern.  If no pattern
+	is supplied, the implied pattern will be ".*" (match anything).
 
-	NP: Using -1 here will override any quick_abort settings that may
-	    otherwise apply to the range request. The range request will
+	NP: Using -1 as the byte value here will override any quick_abort settings 
+		that may otherwise apply to the range request. The range request will
 	    be fully fetched from start to finish regardless of the client
 	    actions. This affects bandwidth usage.
 DOC_END

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2009-11-01 00:13:06 +0000
+++ src/client_side.cc	2009-11-04 17:42:37 +0000
@@ -104,6 +104,7 @@
 #include "MemBuf.h"
 #include "SquidTime.h"
 #include "ChunkedCodingParser.h"
+#include "rangeOffsetLimit.h"
 #include "eui/Config.h"
 
 #if LINGERING_CLOSE
@@ -1107,6 +1108,8 @@
     assert(request->range);
     /* check if we still want to do ranges */
 
+    int64_t roffLimit = getRangeOffsetLimit(request->canonical);
+
     if (!rep)
         range_err = "no [parse-able] reply";
     else if ((rep->sline.status != HTTP_OK) && (rep->sline.status != HTTP_PARTIAL_CONTENT))
@@ -1127,7 +1130,7 @@
         range_err = "canonization failed";
     else if (http->request->range->isComplex())
         range_err = "too complex range header";
-    else if (!logTypeIsATcpHit(http->logType) && http->request->range->offsetLimitExceeded())
+    else if (!logTypeIsATcpHit(http->logType) && http->request->range->offsetLimitExceeded(roffLimit))
         range_err = "range outside range_offset_limit";
 
     /* get rid of our range specs on error */

=== modified file 'src/http.cc'
--- src/http.cc	2009-11-03 10:01:15 +0000
+++ src/http.cc	2009-11-04 17:42:37 +0000
@@ -1896,8 +1896,10 @@
      *  the server and fetch only the requested content)
      */
 
+    int64_t roffLimit = getRangeOffsetLimit(orig_request->canonical);
+
     if (NULL == orig_request->range || !orig_request->flags.cachable
-            || orig_request->range->offsetLimitExceeded() || orig_request->flags.connection_auth)
+            || orig_request->range->offsetLimitExceeded(roffLimit) || orig_request->flags.connection_auth)
         result = false;
 
     debugs(11, 8, "decideIfWeDoRanges: range specs: " <<

=== modified file 'src/http.h'
--- src/http.h	2009-07-02 16:36:36 +0000
+++ src/http.h	2009-10-13 21:10:05 +0000
@@ -39,6 +39,7 @@
 #include "forward.h"
 #include "Server.h"
 #include "ChunkedCodingParser.h"
+#include "rangeOffsetLimit.h"
 
 class HttpStateData : public ServerStateData
 {

=== added file 'src/rangeOffsetLimit.cc'
--- src/rangeOffsetLimit.cc	1970-01-01 00:00:00 +0000
+++ src/rangeOffsetLimit.cc	2009-10-23 15:32:25 +0000
@@ -0,0 +1,15 @@
+#include "rangeOffsetLimit.h"
+#include "stdlib.h"
+
+const int64_t
+getRangeOffsetLimit(const char * uri)
+{
+
+    const range_offset_t *R;
+    for (R = Config.rangeOffsetLimit; R; R = R->next) {
+    	if (!regexec(&(R->compiled_pattern), uri, 0, 0, 0)) {
+    		return R->limit;
+    	}
+    }
+    return (int64_t)0;
+}

=== added file 'src/rangeOffsetLimit.h'
--- src/rangeOffsetLimit.h	1970-01-01 00:00:00 +0000
+++ src/rangeOffsetLimit.h	2009-10-13 21:10:05 +0000
@@ -0,0 +1,8 @@
+#ifndef SQUID_RANGEOFFSETLIMIT_H
+#define SQUID_RANGEOFFSETLIMIT_H
+
+#include "squid.h"
+
+const int64_t getRangeOffsetLimit(const char * uri);
+
+#endif

=== modified file 'src/store_client.cc'
--- src/store_client.cc	2009-08-23 09:30:49 +0000
+++ src/store_client.cc	2009-10-13 21:10:05 +0000
@@ -47,6 +47,7 @@
 #endif
 #include "HttpRequest.h"
 #include "MemBuf.h"
+#include "rangeOffsetLimit.h"
 
 /*
  * NOTE: 'Header' refers to the swapfile metadata header.
@@ -796,7 +797,9 @@
         return 0;
     }
 
-    if ( Config.rangeOffsetLimit < 0 && mem->request && mem->request->range ) {
+    int64_t roffLimit = getRangeOffsetLimit(mem->url);
+
+    if ( roffLimit < 0 && mem->request && mem->request->range ) {
         /* Don't abort if the admin has configured range_ofset -1 to download fully for caching. */
         debugs(90, 3, "CheckQuickAbort2: NO admin configured range replies to full-download");
         return 0;

=== modified file 'src/structs.h'
--- src/structs.h	2009-09-25 11:09:37 +0000
+++ src/structs.h	2009-10-23 15:54:40 +0000
@@ -548,7 +548,7 @@
     } comm_incoming;
     int max_open_disk_fds;
     int uri_whitespace;
-    int64_t rangeOffsetLimit;
+    range_offset_t *rangeOffsetLimit;
 #if MULTICAST_MISS_STREAM
 
     struct {
@@ -1326,4 +1326,16 @@
     customlog_type type;
 };
 
+struct _range_offset_t {
+    const char *pattern;
+    regex_t compiled_pattern;
+    int64_t limit;
+    range_offset_t * next;
+
+    struct{
+        unsigned int icase:1;
+    } flags;
+};
+
+
 #endif /* SQUID_STRUCTS_H */

=== modified file 'src/typedefs.h'
--- src/typedefs.h	2009-07-27 21:50:59 +0000
+++ src/typedefs.h	2009-10-13 21:10:05 +0000
@@ -153,6 +153,8 @@
 
 typedef struct _refresh_t refresh_t;
 
+typedef struct _range_offset_t range_offset_t;
+
 typedef struct _CommWriteStateData CommWriteStateData;
 
 typedef struct _StatCounters StatCounters;

# Begin bundle
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
SKcKEgvFDQHg

