Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 | 1x 1x 1x 1x 1x 1x 1x | import { dispose, DisposableLike } from "@reactive-js/core/lib/disposable"; import { pipe, identity, Function1 } from "@reactive-js/core/lib/functions"; import { ObservableLike, fromValue, map, switchMap, concatMap, } from "@reactive-js/core/lib/observable"; import { isSome } from "@reactive-js/core/lib/option"; import { createRedirectHttpRequest } from "./httpRequest"; import { HttpContentEncoding, HttpRequest, HttpResponse, HttpStatusCode, } from "./interfaces"; export const enum HttpClientRequestStatusType { Start = 1, Progress = 2, Completed = 3, HeadersReceived = 4, } export type HttpClientRequestStatusStart = { readonly type: HttpClientRequestStatusType.Start; }; export type HttpClientRequestStatusProgress = { readonly type: HttpClientRequestStatusType.Progress; readonly count: number; }; export type HttpClientRequestStatusComplete = { readonly type: HttpClientRequestStatusType.Completed; }; export type HttpClientRequestStatusHeadersReceived< TResp extends DisposableLike > = { readonly type: HttpClientRequestStatusType.HeadersReceived; readonly response: HttpResponse<TResp>; }; export type HttpClientRequestStatus<TResp extends DisposableLike> = | HttpClientRequestStatusStart | HttpClientRequestStatusProgress | HttpClientRequestStatusComplete | HttpClientRequestStatusHeadersReceived<TResp>; export type HttpClientRequest<T> = HttpRequest<T> & { readonly acceptedEncodings?: readonly HttpContentEncoding[]; readonly maxRedirects?: number; }; export type HttpClient< THttpRequest extends HttpClientRequest<unknown>, TResp extends DisposableLike > = (req: THttpRequest) => ObservableLike<HttpClientRequestStatus<TResp>>; const redirectCodes = [ HttpStatusCode.MovedPermanently, HttpStatusCode.Found, HttpStatusCode.SeeOther, HttpStatusCode.TemporaryRedirect, HttpStatusCode.PermanentRedirect, ]; export const withDefaultBehaviors = <TReq, TResp extends DisposableLike>( encodeHttpRequest: Function1< HttpClientRequest<TReq>, HttpClientRequest<TReq> > = identity, ) => ( httpClient: HttpClient<HttpClientRequest<TReq>, TResp>, ): HttpClient<HttpClientRequest<TReq>, TResp> => { const sendRequest = ( request: HttpClientRequest<TReq>, ): ObservableLike<HttpClientRequestStatus<TResp>> => pipe( request, fromValue(), map(encodeHttpRequest), switchMap(httpClient), concatMap(status => { if (status.type === HttpClientRequestStatusType.HeadersReceived) { const { response } = status; const { location, preferences, statusCode } = response; const acceptedEncodings = preferences?.acceptedEncodings ?? []; const shouldRedirect = redirectCodes.includes(statusCode) && isSome(location) && (request?.maxRedirects ?? 10) > 0; const newRequest = shouldRedirect ? createRedirectHttpRequest(request, response) : statusCode === HttpStatusCode.ExpectationFailed ? { ...request, expectContinue: false } : statusCode === HttpStatusCode.UnsupportedMediaType && acceptedEncodings.length > 0 ? { ...request, acceptedEncodings } : request; if (request !== newRequest) { dispose(response.body); return sendRequest(newRequest); } // Fallthrough } return fromValue()(status); }), ); return sendRequest; }; |