From d18d7036788acf2d5ddab608d0352158139de189 Mon Sep 17 00:00:00 2001 From: Robert Newson Date: Wed, 18 Aug 2010 11:41:10 +0000 Subject: COUCHDB-161 - support Range header for attachments. Attachments are upgraded to support the Range header on compaction. git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@986629 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_httpd_db.erl | 46 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) (limited to 'src/couchdb/couch_httpd_db.erl') diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl index 3c7e57c4..ab14a7d1 100644 --- a/src/couchdb/couch_httpd_db.erl +++ b/src/couchdb/couch_httpd_db.erl @@ -20,7 +20,7 @@ -import(couch_httpd, [send_json/2,send_json/3,send_json/4,send_method_not_allowed/2, - start_json_response/2,start_json_response/3, + send_response/4,start_json_response/2,start_json_response/3, send_chunk/2,last_chunk/1,end_json_response/1, start_chunked_response/3, absolute_uri/2, send/2, start_response_length/4]). @@ -862,7 +862,7 @@ couch_doc_open(Db, DocId, Rev, Options) -> % Attachment request handlers -db_attachment_req(#httpd{method='GET'}=Req, Db, DocId, FileNameParts) -> +db_attachment_req(#httpd{method='GET',mochi_req=MochiReq}=Req, Db, DocId, FileNameParts) -> FileName = list_to_binary(mochiweb_util:join(lists:map(fun binary_to_list/1, FileNameParts),"/")), #doc_query_args{ rev=Rev, @@ -925,8 +925,46 @@ db_attachment_req(#httpd{method='GET'}=Req, Db, DocId, FileNameParts) -> AttFun(Att, fun(Seg, _) -> send_chunk(Resp, Seg) end, {ok, Resp}), last_chunk(Resp); _ -> - {ok, Resp} = start_response_length(Req, 200, Headers, Len), - AttFun(Att, fun(Seg, _) -> send(Resp, Seg) end, {ok, Resp}) + #att{data={_,StreamInfo}} = Att, %% layering violation + SupportsRange = case StreamInfo of + [{_,_}|_] -> true; + _ -> false + end, + Ranges = MochiReq:get(range), + HasSingleRange = case Ranges of + [_] -> true; + _ -> false + end, + Headers1 = case SupportsRange of + false ->[{<<"Accept-Ranges">>, <<"none">>}] ++ Headers; + true -> [{<<"Accept-Ranges">>, <<"bytes">>}] ++ Headers + end, + if + Enc == identity andalso SupportsRange == true andalso HasSingleRange == true -> + [{From, To}] = Ranges, + {From1, To1} = case {From, To} of + {none, To} -> + {Len - To - 1, Len - 1}; + {From, none} -> + {From, Len - 1}; + _ -> + {From, To} + end, + if + From < 0 orelse To1 >= Len -> + throw(requested_range_not_satisfiable); + true -> + ok + end, + Headers2 = [{<<"Content-Range">>, + ?l2b(io_lib:format("bytes ~B-~B/~B", [From1, To1, Len]))}] + ++ Headers1, + {ok, Resp} = start_response_length(Req, 206, Headers2, To1 - From1 + 1), + couch_doc:range_att_foldl(Att, From1, To1 + 1, fun(Seg, _) -> send(Resp, Seg) end, {ok, Resp}); + true -> + {ok, Resp} = start_response_length(Req, 200, Headers1, Len), + AttFun(Att, fun(Seg, _) -> send(Resp, Seg) end, {ok, Resp}) + end end end ) -- cgit v1.2.3