1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::io::{Read, copy};
use hyper::{self, Client, Url};
use hyper::client::Body;
use hyper::client::request::Request;
use hyper::header::{Headers,ContentLength,ContentType};
use hyper::mime::Mime;
use hyper::method::Method;
use hyper::net::{Streaming, NetworkConnector, NetworkStream};
use serde::Deserialize;
use serde_json;
use B2Error;
use B2AuthHeader;
use raw::authorize::B2Authorization;
use raw::files::MoreFileInfo;
#[derive(Deserialize,Serialize,Clone,Debug)]
#[serde(rename_all = "camelCase")]
pub struct UploadAuthorization {
pub bucket_id: String,
pub upload_url: String,
pub authorization_token: String
}
impl UploadAuthorization {
pub fn auth_header(&self) -> B2AuthHeader {
B2AuthHeader(self.authorization_token.clone())
}
}
impl<'a> B2Authorization<'a> {
pub fn get_upload_url(&self, bucket_id: &str, client: &Client)
-> Result<UploadAuthorization,B2Error>
{
let url_string: String = format!("{}/b2api/v1/b2_get_upload_url", self.api_url);
let url: &str = &url_string;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct Request<'a> {
bucket_id: &'a str
}
let request = Request {
bucket_id: bucket_id
};
let body: String = serde_json::to_string(&request)?;
let resp = client.post(url)
.body(Body::BufBody(body.as_bytes(), body.len()))
.header(self.auth_header())
.send()?;
if resp.status != hyper::status::StatusCode::Ok {
Err(B2Error::from_response(resp))
} else {
Ok(serde_json::from_reader(resp)?)
}
}
}
impl UploadAuthorization {
pub fn upload_file<InfoType, R: Read, C, S>(&self, file: &mut R, file_name: String, content_type: Option<Mime>,
content_length: u64, content_sha1: String, connector: &C)
-> Result<MoreFileInfo<InfoType>, B2Error>
where for<'de> InfoType: Deserialize<'de>, R: Sized, C: NetworkConnector<Stream=S>,
S: Into<Box<NetworkStream + Send>>
{
let mut ufr = self.create_upload_file_request(
file_name, content_type, content_length, content_sha1, connector)?;
copy(file, &mut ufr)?;
ufr.finish()
}
pub fn create_upload_file_request<C,S>(&self, file_name: String,
content_type: Option<Mime>,
content_length: u64, content_sha1: String,
connector: &C)
-> Result<UploadFileRequest, B2Error>
where C: NetworkConnector<Stream=S>, S: Into<Box<NetworkStream + Send>>
{
let url: Url = Url::parse(&self.upload_url)?;
let mut request = Request::with_connector(Method::Post, url, connector)?;
{
let headers: &mut Headers = request.headers_mut();
headers.set(self.auth_header());
headers.set(XBzFileName(file_name));
headers.set(XBzContentSha1(content_sha1));
headers.set(ContentLength(content_length));
headers.set(ContentType(match content_type {
Some(v) => v,
None => "b2/x-auto".parse().unwrap()
}));
}
Ok(UploadFileRequest { request: request.start()? })
}
}
header! { (XBzFileName, "X-Bz-File-Name") => [String] }
header! { (XBzContentSha1, "X-Bz-Content-Sha1") => [String] }
pub struct UploadFileRequest {
request: Request<Streaming>
}
impl ::std::io::Write for UploadFileRequest {
fn write(&mut self, msg: &[u8]) -> ::std::io::Result<usize> {
self.request.write(msg)
}
fn flush(&mut self) -> ::std::io::Result<()> {
self.request.flush()
}
fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
self.request.write_all(buf)
}
fn write_fmt(&mut self, fmt: ::core::fmt::Arguments) -> Result<(), ::std::io::Error> {
self.request.write_fmt(fmt)
}
}
impl UploadFileRequest {
pub fn finish<InfoType>(self) -> Result<MoreFileInfo<InfoType>, B2Error>
where for<'de> InfoType: Deserialize<'de>
{
let resp = self.request.send()?;
if resp.status != hyper::status::StatusCode::Ok {
Err(B2Error::from_response(resp))
} else {
Ok(serde_json::from_reader(resp)?)
}
}
}