5
5
use data_loader:: decode;
6
6
use fetch:: cors_cache:: { BasicCORSCache , CORSCache , CacheRequestDetails } ;
7
7
use http_loader:: { NetworkHttpRequestFactory , create_http_connector, obtain_response} ;
8
- use hyper:: header:: { Accept , CacheControl , IfMatch , IfRange , IfUnmodifiedSince , Location } ;
9
- use hyper:: header:: { AcceptLanguage , ContentLength , ContentLanguage , HeaderView , Pragma } ;
10
- use hyper:: header:: { AccessControlAllowCredentials , AccessControlAllowOrigin } ;
11
- use hyper:: header:: { Authorization , Basic , CacheDirective , ContentEncoding , Encoding } ;
12
- use hyper:: header:: { ContentType , Headers , IfModifiedSince , IfNoneMatch } ;
13
- use hyper:: header:: { QualityItem , q , qitem , Referer as RefererHeader , UserAgent } ;
8
+ use hyper:: header:: { Accept , AcceptLanguage , Authorization , AccessControlAllowCredentials } ;
9
+ use hyper:: header:: { AccessControlAllowOrigin , AccessControlAllowHeaders , AccessControlAllowMethods } ;
10
+ use hyper:: header:: { AccessControlRequestHeaders , AccessControlMaxAge , AccessControlRequestMethod , Basic } ;
11
+ use hyper:: header:: { CacheControl , CacheDirective , ContentEncoding , ContentLength , ContentLanguage , ContentType } ;
12
+ use hyper:: header:: { Encoding , HeaderView , Headers , IfMatch , IfRange , IfUnmodifiedSince , IfModifiedSince } ;
13
+ use hyper:: header:: { IfNoneMatch , Pragma , Location , QualityItem , Referer as RefererHeader , UserAgent , q , qitem } ;
14
14
use hyper:: method:: Method ;
15
15
use hyper:: mime:: { Mime , SubLevel , TopLevel } ;
16
16
use hyper:: status:: StatusCode ;
@@ -20,9 +20,12 @@ use net_traits::request::{RedirectMode, Referer, Request, RequestMode, ResponseT
20
20
use net_traits:: response:: { HttpsState , TerminationReason } ;
21
21
use net_traits:: response:: { Response , ResponseBody , ResponseType } ;
22
22
use resource_thread:: CancellationListener ;
23
+ use std:: collections:: HashSet ;
23
24
use std:: io:: Read ;
25
+ use std:: iter:: FromIterator ;
24
26
use std:: rc:: Rc ;
25
27
use std:: thread;
28
+ use unicase:: UniCase ;
26
29
use url:: idna:: domain_to_ascii;
27
30
use url:: { Origin as UrlOrigin , OpaqueOrigin , Url , UrlParser , whatwg_scheme_type_mapper} ;
28
31
use util:: thread:: spawn_named;
@@ -210,7 +213,7 @@ fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Re
210
213
let internal_response = if response. is_network_error ( ) {
211
214
& network_error_res
212
215
} else {
213
- response. get_actual_response ( )
216
+ response. actual_response ( )
214
217
} ;
215
218
216
219
// Step 13
@@ -245,7 +248,7 @@ fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Re
245
248
246
249
// Step 16
247
250
if request. synchronous {
248
- response. get_actual_response ( ) . wait_until_done ( ) ;
251
+ response. actual_response ( ) . wait_until_done ( ) ;
249
252
return response;
250
253
}
251
254
@@ -263,7 +266,7 @@ fn main_fetch(request: Rc<Request>, cors_flag: bool, recursive_flag: bool) -> Re
263
266
let internal_response = if response. is_network_error ( ) {
264
267
& network_error_res
265
268
} else {
266
- response. get_actual_response ( )
269
+ response. actual_response ( )
267
270
} ;
268
271
269
272
// Step 18
@@ -365,7 +368,7 @@ fn http_fetch(request: Rc<Request>,
365
368
}
366
369
367
370
// Substep 4
368
- let actual_response = res. get_actual_response ( ) ;
371
+ let actual_response = res. actual_response ( ) ;
369
372
if actual_response. url_list . borrow ( ) . is_empty ( ) {
370
373
* actual_response. url_list . borrow_mut ( ) = request. url_list . borrow ( ) . clone ( ) ;
371
374
}
@@ -390,7 +393,7 @@ fn http_fetch(request: Rc<Request>,
390
393
} , request. method . borrow ( ) . clone ( ) ) ;
391
394
392
395
let method_mismatch = !method_cache_match && ( !is_simple_method ( & request. method . borrow ( ) ) ||
393
- request. use_cors_preflight ) ;
396
+ request. use_cors_preflight ) ;
394
397
let header_mismatch = request. headers . borrow ( ) . iter ( ) . any ( |view|
395
398
!cache. match_header ( CacheRequestDetails {
396
399
origin : origin. clone ( ) ,
@@ -401,7 +404,7 @@ fn http_fetch(request: Rc<Request>,
401
404
402
405
// Sub-substep 1
403
406
if method_mismatch || header_mismatch {
404
- let preflight_result = preflight_fetch ( request. clone ( ) ) ;
407
+ let preflight_result = cors_preflight_fetch ( request. clone ( ) , Some ( cache ) ) ;
405
408
// Sub-substep 2
406
409
if preflight_result. response_type == ResponseType :: Error {
407
410
return Response :: network_error ( ) ;
@@ -415,8 +418,7 @@ fn http_fetch(request: Rc<Request>,
415
418
// Substep 3
416
419
let credentials = match request. credentials_mode {
417
420
CredentialsMode :: Include => true ,
418
- CredentialsMode :: CredentialsSameOrigin if
419
- request. response_tainting . get ( ) == ResponseTainting :: Basic
421
+ CredentialsMode :: CredentialsSameOrigin if request. response_tainting . get ( ) == ResponseTainting :: Basic
420
422
=> true ,
421
423
_ => false
422
424
} ;
@@ -437,7 +439,7 @@ fn http_fetch(request: Rc<Request>,
437
439
let mut response = response. unwrap ( ) ;
438
440
439
441
// Step 5
440
- match response. get_actual_response ( ) . status . unwrap ( ) {
442
+ match response. actual_response ( ) . status . unwrap ( ) {
441
443
442
444
// Code 301, 302, 303, 307, 308
443
445
StatusCode :: MovedPermanently | StatusCode :: Found | StatusCode :: SeeOther |
@@ -518,21 +520,21 @@ fn http_redirect_fetch(request: Rc<Request>,
518
520
assert_eq ! ( response. return_internal. get( ) , true ) ;
519
521
520
522
// Step 3
521
- // this step is done early, because querying if Location is available says
523
+ // this step is done early, because querying if Location exists says
522
524
// if it is None or Some, making it easy to seperate from the retrieval failure case
523
- if !response. get_actual_response ( ) . headers . has :: < Location > ( ) {
525
+ if !response. actual_response ( ) . headers . has :: < Location > ( ) {
524
526
return Rc :: try_unwrap ( response) . ok ( ) . unwrap ( ) ;
525
527
}
526
528
527
529
// Step 2
528
- let location = match response. get_actual_response ( ) . headers . get :: < Location > ( ) {
530
+ let location = match response. actual_response ( ) . headers . get :: < Location > ( ) {
529
531
Some ( & Location ( ref location) ) => location. clone ( ) ,
530
532
// Step 4
531
533
_ => return Response :: network_error ( )
532
534
} ;
533
535
534
536
// Step 5
535
- let response_url = response. get_actual_response ( ) . url . as_ref ( ) . unwrap ( ) ;
537
+ let response_url = response. actual_response ( ) . url . as_ref ( ) . unwrap ( ) ;
536
538
let location_url = UrlParser :: new ( ) . base_url ( response_url) . parse ( & * location) ;
537
539
538
540
// Step 6
@@ -575,7 +577,7 @@ fn http_redirect_fetch(request: Rc<Request>,
575
577
}
576
578
577
579
// Step 13
578
- let status_code = response. get_actual_response ( ) . status . unwrap ( ) ;
580
+ let status_code = response. actual_response ( ) . status . unwrap ( ) ;
579
581
if ( ( status_code == StatusCode :: MovedPermanently || status_code == StatusCode :: Found ) &&
580
582
* request. method . borrow ( ) == Method :: Post ) ||
581
583
status_code == StatusCode :: SeeOther {
@@ -876,11 +878,11 @@ fn http_network_fetch(request: Rc<Request>,
876
878
877
879
// Substep 2
878
880
879
- // TODO how can I tell if response was retrieved over HTTPS?
881
+ // TODO Determine if response was retrieved over HTTPS
880
882
// TODO Servo needs to decide what ciphers are to be treated as "deprecated"
881
883
response. https_state = HttpsState :: None ;
882
884
883
- // TODO how do I read request?
885
+ // TODO Read request
884
886
885
887
// Step 5
886
888
// TODO when https://bugzilla.mozilla.org/show_bug.cgi?id=1030660
@@ -925,35 +927,139 @@ fn http_network_fetch(request: Rc<Request>,
925
927
}
926
928
927
929
/// [CORS preflight fetch](https://fetch.spec.whatwg.org#cors-preflight-fetch)
928
- fn preflight_fetch ( _request : Rc < Request > ) -> Response {
929
- // TODO: Implement preflight fetch spec
930
+ fn cors_preflight_fetch ( request : Rc < Request > , cache : Option < BasicCORSCache > ) -> Response {
931
+ // Step 1
932
+ let mut preflight = Request :: new ( request. current_url ( ) , Some ( request. origin . borrow ( ) . clone ( ) ) , false ) ;
933
+ * preflight. method . borrow_mut ( ) = Method :: Options ;
934
+ preflight. initiator = request. initiator . clone ( ) ;
935
+ preflight. type_ = request. type_ . clone ( ) ;
936
+ preflight. destination = request. destination . clone ( ) ;
937
+ preflight. referer = request. referer . clone ( ) ;
938
+
939
+ // Step 2
940
+ preflight. headers . borrow_mut ( ) . set :: < AccessControlRequestMethod > (
941
+ AccessControlRequestMethod ( request. method . borrow ( ) . clone ( ) ) ) ;
942
+
943
+ // Step 3, 4
944
+ let mut value = request. headers . borrow ( ) . iter ( )
945
+ . filter_map ( |ref view| if is_simple_header ( view) {
946
+ None
947
+ } else {
948
+ Some ( UniCase ( view. name ( ) . to_owned ( ) ) )
949
+ } ) . collect :: < Vec < UniCase < String > > > ( ) ;
950
+ value. sort ( ) ;
951
+
952
+ // Step 5
953
+ preflight. headers . borrow_mut ( ) . set :: < AccessControlRequestHeaders > (
954
+ AccessControlRequestHeaders ( value) ) ;
955
+
956
+ // Step 6
957
+ let preflight = Rc :: new ( preflight) ;
958
+ let response = http_network_or_cache_fetch ( preflight. clone ( ) , false , false ) ;
959
+
960
+ // Step 7
961
+ if cors_check ( request. clone ( ) , & response) . is_ok ( ) &&
962
+ response. status . map_or ( false , |status| status. is_success ( ) ) {
963
+ // Substep 1
964
+ let mut methods = if response. headers . has :: < AccessControlAllowMethods > ( ) {
965
+ match response. headers . get :: < AccessControlAllowMethods > ( ) {
966
+ Some ( & AccessControlAllowMethods ( ref m) ) => m. clone ( ) ,
967
+ // Substep 3
968
+ None => return Response :: network_error ( )
969
+ }
970
+ } else {
971
+ vec ! [ ]
972
+ } ;
973
+
974
+ // Substep 2
975
+ let header_names = if response. headers . has :: < AccessControlAllowHeaders > ( ) {
976
+ match response. headers . get :: < AccessControlAllowHeaders > ( ) {
977
+ Some ( & AccessControlAllowHeaders ( ref hn) ) => hn. clone ( ) ,
978
+ // Substep 3
979
+ None => return Response :: network_error ( )
980
+ }
981
+ } else {
982
+ vec ! [ ]
983
+ } ;
984
+
985
+ // Substep 4
986
+ if methods. is_empty ( ) && request. use_cors_preflight {
987
+ methods = vec ! [ request. method. borrow( ) . clone( ) ] ;
988
+ }
989
+
990
+ // Substep 5
991
+ if methods. iter ( ) . all ( |method| * method != * request. method . borrow ( ) ) &&
992
+ !is_simple_method ( & * request. method . borrow ( ) ) {
993
+ return Response :: network_error ( ) ;
994
+ }
995
+
996
+ // Substep 6
997
+ let set: HashSet < & UniCase < String > > = HashSet :: from_iter ( header_names. iter ( ) ) ;
998
+ if request. headers . borrow ( ) . iter ( ) . any ( |ref hv| !set. contains ( & UniCase ( hv. name ( ) . to_owned ( ) ) ) &&
999
+ !is_simple_header ( hv) ) {
1000
+ return Response :: network_error ( ) ;
1001
+ }
1002
+
1003
+ // Substep 7, 8
1004
+ let max_age = response. headers . get :: < AccessControlMaxAge > ( ) . map ( |acma| acma. 0 ) . unwrap_or ( 0 ) ;
1005
+
1006
+ // TODO: Substep 9 - Need to define what an imposed limit on max-age is
1007
+
1008
+ // Substep 10
1009
+ let mut cache = match cache {
1010
+ Some ( c) => c,
1011
+ None => return response
1012
+ } ;
1013
+
1014
+ // Substep 11, 12
1015
+ for method in & methods {
1016
+ cache. match_method_and_update ( CacheRequestDetails {
1017
+ origin : request. origin . borrow ( ) . clone ( ) ,
1018
+ destination : request. current_url ( ) ,
1019
+ credentials : request. credentials_mode == CredentialsMode :: Include
1020
+ } , method. clone ( ) , max_age) ;
1021
+ }
1022
+
1023
+ // Substep 13, 14
1024
+ for header_name in & header_names {
1025
+ cache. match_header_and_update ( CacheRequestDetails {
1026
+ origin : request. origin . borrow ( ) . clone ( ) ,
1027
+ destination : request. current_url ( ) ,
1028
+ credentials : request. credentials_mode == CredentialsMode :: Include
1029
+ } , & * header_name, max_age) ;
1030
+ }
1031
+
1032
+ // Substep 15
1033
+ return response;
1034
+ }
1035
+
1036
+ // Step 8
930
1037
Response :: network_error ( )
931
1038
}
932
1039
933
1040
/// [CORS check](https://fetch.spec.whatwg.org#concept-cors-check)
934
1041
fn cors_check ( request : Rc < Request > , response : & Response ) -> Result < ( ) , ( ) > {
935
1042
936
1043
// Step 1
937
- // let headers = request.headers.borrow();
938
1044
let origin = response. headers . get :: < AccessControlAllowOrigin > ( ) . cloned ( ) ;
939
1045
940
1046
// Step 2
941
1047
let origin = try!( origin. ok_or ( ( ) ) ) ;
942
1048
943
1049
// Step 3
944
1050
if request. credentials_mode != CredentialsMode :: Include &&
945
- origin == AccessControlAllowOrigin :: Any {
1051
+ origin == AccessControlAllowOrigin :: Any {
946
1052
return Ok ( ( ) ) ;
947
1053
}
948
1054
949
1055
// Step 4
950
1056
let origin = match origin {
951
1057
AccessControlAllowOrigin :: Value ( origin) => origin,
952
- // if it's Any or Null at this point, I see nothing to do but return Err(())
1058
+ // if it's Any or Null at this point, there's nothing to do but return Err(())
953
1059
_ => return Err ( ( ) )
954
1060
} ;
955
1061
956
- // strings are already utf-8 encoded, so I don't need to re-encode origin for this step
1062
+ // strings are already utf-8 encoded, so there's no need to re-encode origin for this step
957
1063
match ascii_serialise_origin ( & request. origin . borrow ( ) ) {
958
1064
Ok ( request_origin) => {
959
1065
if request_origin != origin {
0 commit comments