mirror of
https://github.com/mozilla-services/syncstorage-rs.git
synced 2026-05-05 20:26:26 +02:00
Merge pull request #107 from mozilla-services/feat/issue-99
feat: return newlines reply when get accept header indicates it
This commit is contained in:
commit
d392e95e06
@ -12,6 +12,7 @@ use web::extractors::RequestErrorLocation;
|
||||
|
||||
/// Legacy Sync 1.1 error codes, which Sync 1.5 also returns by replacing the descriptive JSON
|
||||
/// information and replacing it with one of these error codes.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Serialize)]
|
||||
enum WeaveError {
|
||||
/// Unknown error
|
||||
|
||||
@ -106,10 +106,13 @@ impl From<Context<ValidationErrorKind>> for ValidationError {
|
||||
fn from(inner: Context<ValidationErrorKind>) -> Self {
|
||||
let status = match inner.get_context() {
|
||||
ValidationErrorKind::FromDetails(ref _description, ref location, Some(ref name))
|
||||
if *location == RequestErrorLocation::Header
|
||||
&& name.eq_ignore_ascii_case("Content-Type") =>
|
||||
if *location == RequestErrorLocation::Header =>
|
||||
{
|
||||
StatusCode::UNSUPPORTED_MEDIA_TYPE
|
||||
match name.to_ascii_lowercase().as_str() {
|
||||
"accept" => StatusCode::NOT_ACCEPTABLE,
|
||||
"content-type" => StatusCode::UNSUPPORTED_MEDIA_TYPE,
|
||||
_ => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
_ => StatusCode::BAD_REQUEST,
|
||||
};
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
use actix_web::http::header::{HeaderValue, CONTENT_TYPE};
|
||||
use actix_web::http::header::{HeaderValue, ACCEPT, CONTENT_TYPE};
|
||||
use actix_web::{
|
||||
dev::{JsonConfig, PayloadConfig},
|
||||
error::ErrorInternalServerError,
|
||||
@ -391,6 +391,13 @@ impl FromRequest<ServerState> for MetaRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/// Desired reply format for a Collection Get request
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ReplyFormat {
|
||||
Json,
|
||||
Newlines,
|
||||
}
|
||||
|
||||
/// Collection Request Delete/Get extractor
|
||||
///
|
||||
/// Extracts/validates information needed for collection delete/get requests.
|
||||
@ -399,6 +406,7 @@ pub struct CollectionRequest {
|
||||
pub db: Box<dyn Db>,
|
||||
pub user_id: HawkIdentifier,
|
||||
pub query: BsoQueryParams,
|
||||
pub reply: ReplyFormat,
|
||||
}
|
||||
|
||||
impl FromRequest<ServerState> for CollectionRequest {
|
||||
@ -410,12 +418,25 @@ impl FromRequest<ServerState> for CollectionRequest {
|
||||
let db = <Box<dyn Db>>::from_request(req, settings)?;
|
||||
let query = BsoQueryParams::from_request(req, settings)?;
|
||||
let collection = CollectionParam::from_request(req, settings)?.collection;
|
||||
let reply = match req.headers().get(ACCEPT) {
|
||||
Some(v) if v.as_bytes() == b"application/newlines" => ReplyFormat::Newlines,
|
||||
Some(v) if v.as_bytes() == b"application/json" => ReplyFormat::Json,
|
||||
Some(_) => {
|
||||
return Err(ValidationErrorKind::FromDetails(
|
||||
"Invalid accept".to_string(),
|
||||
RequestErrorLocation::Header,
|
||||
Some("accept".to_string()),
|
||||
).into());
|
||||
}
|
||||
None => ReplyFormat::Json,
|
||||
};
|
||||
|
||||
Ok(CollectionRequest {
|
||||
collection,
|
||||
db,
|
||||
user_id,
|
||||
query,
|
||||
reply,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ use error::ApiError;
|
||||
use server::ServerState;
|
||||
use web::extractors::{
|
||||
BsoPutRequest, BsoRequest, CollectionPostRequest, CollectionRequest, HawkIdentifier,
|
||||
MetaRequest,
|
||||
MetaRequest, ReplyFormat,
|
||||
};
|
||||
|
||||
pub const ONE_KB: f64 = 1024.0;
|
||||
@ -128,6 +128,7 @@ where
|
||||
F: Future<Item = Paginated<T>, Error = ApiError> + 'static,
|
||||
T: Serialize + Default + 'static,
|
||||
{
|
||||
let reply_format = coll.reply;
|
||||
Box::new(
|
||||
fut.or_else(move |e| {
|
||||
if e.is_colllection_not_found() {
|
||||
@ -143,13 +144,29 @@ where
|
||||
.extract_resource(coll.user_id, Some(coll.collection), None)
|
||||
.map_err(From::from)
|
||||
.map(move |ts| (result, ts))
|
||||
}).map(|(result, ts)| {
|
||||
HttpResponse::build(StatusCode::OK)
|
||||
}).map(move |(result, ts)| {
|
||||
let mut builder = HttpResponse::build(StatusCode::OK);
|
||||
let resp = builder
|
||||
.header("X-Last-Modified", ts.as_header())
|
||||
.header("X-Weave-Records", result.items.len().to_string())
|
||||
.if_some(result.offset, |offset, resp| {
|
||||
resp.header("X-Weave-Next-Offset", offset.to_string());
|
||||
}).json(result.items)
|
||||
});
|
||||
match reply_format {
|
||||
ReplyFormat::Json => resp.json(result.items),
|
||||
ReplyFormat::Newlines => {
|
||||
let items: String = result
|
||||
.items
|
||||
.into_iter()
|
||||
.map(|v| serde_json::to_string(&v).unwrap_or("".to_string()))
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(|v| v.replace("\n", "\\u000a") + "\n")
|
||||
.collect();
|
||||
resp.header("Content-Type", "application/newlines")
|
||||
.header("Content-Length", format!("{}", items.len()))
|
||||
.body(items)
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user