summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2010-08-25 08:17:19 +0000
committerRobert Newson <rnewson@apache.org>2010-08-25 08:17:19 +0000
commit6f77afd486bdf07e800d47eddc7cf6249e5386e8 (patch)
tree162edcc228768425958beb9cf503bddcee81ea11
parent808d2b79f3b1075f4480e2d628d737f4ac82aba2 (diff)
COUCHDB-161 - range support. Adhere closer to the spec. correct range parsing error in mochiweb.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@988866 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--share/www/script/test/attachment_ranges.js40
-rw-r--r--src/couchdb/couch_httpd_db.erl28
-rw-r--r--src/mochiweb/mochiweb_http.erl2
3 files changed, 40 insertions, 30 deletions
diff --git a/share/www/script/test/attachment_ranges.js b/share/www/script/test/attachment_ranges.js
index 807a13c8..748a979e 100644
--- a/share/www/script/test/attachment_ranges.js
+++ b/share/www/script/test/attachment_ranges.js
@@ -37,28 +37,29 @@ couchTests.attachment_ranges = function(debug) {
"Range": "bytes=0-28"
}
});
- TEquals(206, xhr.status);
+ TEquals(206, xhr.status, "fetch 0-28");
TEquals("This is a base64 encoded text", xhr.responseText);
TEquals("bytes 0-28/29", xhr.getResponseHeader("Content-Range"));
TEquals("29", xhr.getResponseHeader("Content-Length"));
- // Fetch the whole entity without an end offset is a 200.
+ // Fetch the whole entity without an end offset is a 206.
var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt", {
headers: {
"Range": "bytes=0-"
}
});
- TEquals(200, xhr.status);
+ TEquals(206, xhr.status, "fetch 0-");
TEquals("This is a base64 encoded text", xhr.responseText);
+ TEquals("bytes 0-28/29", xhr.getResponseHeader("Content-Range"));
TEquals("29", xhr.getResponseHeader("Content-Length"));
- // Badly formed range header is a 400.
+ // Badly formed range header is a 200.
var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt", {
headers: {
"Range": "bytes:0-"
}
});
- TEquals(400, xhr.status);
+ TEquals(200, xhr.status, "fetch with bad range header");
// Fetch the end of an entity without an end offset is a 206.
var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt", {
@@ -66,18 +67,20 @@ couchTests.attachment_ranges = function(debug) {
"Range": "bytes=2-"
}
});
- TEquals(206, xhr.status);
+ TEquals(206, xhr.status, "fetch 2-");
TEquals("is is a base64 encoded text", xhr.responseText);
TEquals("bytes 2-28/29", xhr.getResponseHeader("Content-Range"));
TEquals("27", xhr.getResponseHeader("Content-Length"));
- // Fetch past the end of the entity is a 416
+ // Fetch past the end of the entity is a 206
var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt", {
headers: {
"Range": "bytes=0-29"
}
});
- TEquals(416, xhr.status);
+ TEquals(206, xhr.status, "fetch 0-29");
+ TEquals("bytes 0-28/29", xhr.getResponseHeader("Content-Range"));
+ TEquals("29", xhr.getResponseHeader("Content-Length"));
// Fetch first part of entity is a 206
var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt", {
@@ -85,7 +88,7 @@ couchTests.attachment_ranges = function(debug) {
"Range": "bytes=0-3"
}
});
- TEquals(206, xhr.status);
+ TEquals(206, xhr.status, "fetch 0-3");
TEquals("This", xhr.responseText);
TEquals("4", xhr.getResponseHeader("Content-Length"));
TEquals("bytes 0-3/29", xhr.getResponseHeader("Content-Range"));
@@ -96,7 +99,7 @@ couchTests.attachment_ranges = function(debug) {
"Range": "bytes=10-15"
}
});
- TEquals(206, xhr.status);
+ TEquals(206, xhr.status, "fetch 10-15");
TEquals("base64", xhr.responseText);
TEquals("6", xhr.getResponseHeader("Content-Length"));
TEquals("bytes 10-15/29", xhr.getResponseHeader("Content-Range"));
@@ -107,10 +110,25 @@ couchTests.attachment_ranges = function(debug) {
"Range": "bytes=-3"
}
});
- TEquals(206, xhr.status);
+ TEquals(206, xhr.status, "fetch -3");
TEquals("ext", xhr.responseText);
TEquals("3", xhr.getResponseHeader("Content-Length"));
TEquals("bytes 26-28/29", xhr.getResponseHeader("Content-Range"));
+
+ // backward range is 416
+ var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt", {
+ headers: {
+ "Range": "bytes=5-3"
+ }
+ });
+ TEquals(416, xhr.status, "fetch 5-3");
+ // range completely outside of entity is 416
+ var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt", {
+ headers: {
+ "Range": "bytes=300-310"
+ }
+ });
+ TEquals(416, xhr.status, "fetch 300-310");
};
diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl
index 0479c9c1..4002a6a9 100644
--- a/src/couchdb/couch_httpd_db.erl
+++ b/src/couchdb/couch_httpd_db.erl
@@ -1086,29 +1086,23 @@ db_attachment_req(Req, _Db, _DocId, _FileNameParts) ->
parse_ranges(undefined, _Len) ->
undefined;
-parse_ranges(fail, _Len) ->
- throw(bad_request);
+parse_ranges(fail, Len) ->
+ undefined;
parse_ranges(Ranges, Len) ->
parse_ranges(Ranges, Len, []).
parse_ranges([], _Len, Acc) ->
lists:reverse(Acc);
+parse_ranges([{From, To}|_], Len, _Acc) when is_integer(From) andalso is_integer(To) andalso To < From ->
+ throw(requested_range_not_satisfiable);
+parse_ranges([{From, To}|Rest], Len, Acc) when is_integer(To) andalso To >= Len ->
+ parse_ranges([{From, Len-1}] ++ Rest, Len, Acc);
+parse_ranges([{none, To}|Rest], Len, Acc) ->
+ parse_ranges([{Len - To, Len - 1}] ++ Rest, Len, Acc);
+parse_ranges([{From, none}|Rest], Len, Acc) ->
+ parse_ranges([{From, Len - 1}] ++ Rest, Len, Acc);
parse_ranges([{From,To}|Rest], Len, Acc) ->
- {From1, To1} = case {From, To} of
- {none, To} ->
- {Len - To, Len - 1};
- {From, none} ->
- {From, Len - 1};
- _ ->
- {From, To}
- end,
- if
- From < 0 orelse To1 >= Len ->
- throw(requested_range_not_satisfiable);
- true ->
- ok
- end,
- parse_ranges(Rest, Len, [{From1, To1}] ++ Acc).
+ parse_ranges(Rest, Len, [{From, To}] ++ Acc).
get_md5_header(Req) ->
ContentMD5 = couch_httpd:header_value(Req, "Content-MD5"),
diff --git a/src/mochiweb/mochiweb_http.erl b/src/mochiweb/mochiweb_http.erl
index 24140994..ab0af7e8 100644
--- a/src/mochiweb/mochiweb_http.erl
+++ b/src/mochiweb/mochiweb_http.erl
@@ -162,8 +162,6 @@ after_response(Body, Req) ->
?MODULE:loop(Socket, Body)
end.
-parse_range_request("bytes=0-") ->
- undefined;
parse_range_request(RawRange) when is_list(RawRange) ->
try
"bytes=" ++ RangeString = RawRange,