From 2f3b2d24ce2367356698b902becabb40b8636ab6 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 25 Apr 2015 18:45:37 +0200 Subject: [PATCH] fix(CLI): simple and resumable upload works * fixed boundary syntax of multi-part message. Was --BOUNDARY, now is --BOUNDARY-- * Fixed ContentRange parsing and serialization. We actually managed to break it last time we tried to update it to match the Go implementation. * fixed uploadType header parameter. It's based on chosen protocol and whether or not the method supports multipart operation for the given protocol. Related to #76 --- src/mako/api/lib/mbuild.mako | 24 ++++++++++++++++-------- src/rust/api/cmn.rs | 6 +++--- src/rust/lib.rs | 11 +++++------ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/mako/api/lib/mbuild.mako b/src/mako/api/lib/mbuild.mako index baa9a89e41b..9a8388d17c2 100644 --- a/src/mako/api/lib/mbuild.mako +++ b/src/mako/api/lib/mbuild.mako @@ -496,6 +496,14 @@ match result { % for p in field_params: <% pname = 'self.' + property(p.name) # property identifier + if media_params and 'mediaUpload' in m: + upload_type_map = dict() + for mp in media_params: + if mp.protocol == 'simple': + upload_type_map[mp.protocol] = m.mediaUpload.protocols.simple.multipart and 'multipart' or 'media' + break + # for each meadia param + # end build media param map %>\ ## parts can also be derived from the request, but we do that only if it's not set % if p.name == 'part' and request_value: @@ -561,21 +569,21 @@ match result { % endif ## response schema % if media_params: - let mut url = \ + let (mut url, upload_type) = % for mp in media_params: % if loop.first: -if \ + if \ % else: else if \ % endif protocol == "${mp.protocol}" { - "${join_url(rootUrl, mp.path)}".to_string() + ("${join_url(rootUrl, mp.path)}".to_string(), "${upload_type_map.get(mp.protocol, mp.protocol)}") } \ % endfor else { unreachable!() - }; - params.push(("uploadType", protocol.to_string())); + }; + params.push(("uploadType", upload_type.to_string())); % else: let mut url = "${baseUrl}${m.path}".to_string(); % endif @@ -788,9 +796,9 @@ else { ${READER_SEEK | indent_all_but_first_by(6)} let mut client = &mut *self.hub.client.borrow_mut(); let upload_result = { - let url = &res.headers.get::().expect("Location header is part of protocol").0; + let url_str = &res.headers.get::().expect("Location header is part of protocol").0; if upload_url_from_server { - dlg.store_upload_url(url); + dlg.store_upload_url(url_str); } cmn::ResumableUploadHelper { @@ -800,7 +808,7 @@ else { auth: &mut *self.hub.auth.borrow_mut(), user_agent: &self.hub._user_agent, auth_header: auth_header.clone(), - url: url, + url: url_str, reader: &mut reader, media_type: reader_mime_type.clone(), content_length: size diff --git a/src/rust/api/cmn.rs b/src/rust/api/cmn.rs index 5b7eb4d484e..af20f514967 100644 --- a/src/rust/api/cmn.rs +++ b/src/rust/api/cmn.rs @@ -429,7 +429,7 @@ impl<'a> Read for MultiPartReader<'a> { // before clearing the last part, we will add the boundary that // will be written last self.last_part_boundary = Some(Cursor::new( - format!("{}--{}", LINE_ENDING, BOUNDARY).into_bytes())) + format!("{}--{}--", LINE_ENDING, BOUNDARY).into_bytes())) } // We are depleted - this can trigger the next part to come in self.current_part = None; @@ -517,7 +517,7 @@ impl Header for ContentRange { impl HeaderFormat for ContentRange { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - try!(fmt.write_str("bytes=")); + try!(fmt.write_str("bytes ")); match self.range { Some(ref c) => try!(c.fmt(fmt)), None => try!(fmt.write_str("*")) @@ -538,7 +538,7 @@ impl Header for RangeResponseHeader { fn parse_header(raw: &[Vec]) -> Option { if let [ref v] = raw { if let Ok(s) = std::str::from_utf8(v) { - const PREFIX: &'static str = "bytes="; + const PREFIX: &'static str = "bytes "; if s.starts_with(PREFIX) { if let Ok(c) = ::from_str(&s[PREFIX.len()..]) { return Some(RangeResponseHeader(c)) diff --git a/src/rust/lib.rs b/src/rust/lib.rs index 66cb0bd3b48..94d59956dca 100644 --- a/src/rust/lib.rs +++ b/src/rust/lib.rs @@ -21,7 +21,6 @@ mod test_api { use self::hyper_mock::*; use std::io::Read; use std::default::Default; - use std::old_path::BytesContainer; use hyper; use std::str::FromStr; @@ -38,9 +37,9 @@ Content-Length: 25\r\n\ Content-Type: application/plain\r\n\ \r\n\ bar\r\n\ ---MDuXWGyeE33QFXGchb2VFWc4Z7945d"; +--MDuXWGyeE33QFXGchb2VFWc4Z7945d--"; - const EXPECTED_LEN: usize= 221; + const EXPECTED_LEN: usize= 223; #[test] fn multi_part_reader() { @@ -130,9 +129,9 @@ bar\r\n\ #[test] fn content_range() { for &(ref c, ref expected) in - &[(ContentRange {range: None, total_length: 50 }, "Content-Range: bytes=*/50\r\n"), + &[(ContentRange {range: None, total_length: 50 }, "Content-Range: bytes */50\r\n"), (ContentRange {range: Some(Chunk { first: 23, last: 40 }), total_length: 45}, - "Content-Range: bytes=23-40/45\r\n")] { + "Content-Range: bytes 23-40/45\r\n")] { let mut headers = hyper::header::Headers::new(); headers.set(c.clone()); assert_eq!(headers.to_string(), expected.to_string()); @@ -147,7 +146,7 @@ bar\r\n\ #[test] fn parse_range_response() { - let r: RangeResponseHeader = hyper::header::Header::parse_header(&[b"bytes=2-42".to_vec()]).unwrap(); + let r: RangeResponseHeader = hyper::header::Header::parse_header(&[b"bytes 2-42".to_vec()]).unwrap(); assert_eq!(r.0.first, 2); assert_eq!(r.0.last, 42); }