summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.h
blob: 06e751227f16cb63cedb9665dceaabb432af2868 (plain)
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
/*
 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
 * Copyright (c) 2022, Kenneth Myhra <kennethmyhra@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/ByteBuffer.h>
#include <AK/RefCounted.h>
#include <AK/URL.h>
#include <AK/Weakable.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/Bindings/Wrappable.h>
#include <LibWeb/DOM/EventTarget.h>
#include <LibWeb/DOM/ExceptionOr.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Statuses.h>
#include <LibWeb/MimeSniff/MimeType.h>
#include <LibWeb/URL/URLSearchParams.h>
#include <LibWeb/XHR/XMLHttpRequestEventTarget.h>

namespace Web::XHR {

using XMLHttpRequestBodyInit = Variant<NonnullRefPtr<URL::URLSearchParams>, String>;

class XMLHttpRequest final
    : public RefCounted<XMLHttpRequest>
    , public Weakable<XMLHttpRequest>
    , public XMLHttpRequestEventTarget {
public:
    enum class ReadyState : u16 {
        Unsent = 0,
        Opened = 1,
        HeadersReceived = 2,
        Loading = 3,
        Done = 4,
    };

    struct BodyWithType {
        ByteBuffer body;
        String type;
    };

    using WrapperType = Bindings::XMLHttpRequestWrapper;

    static NonnullRefPtr<XMLHttpRequest> create(HTML::Window& window)
    {
        return adopt_ref(*new XMLHttpRequest(window));
    }
    static NonnullRefPtr<XMLHttpRequest> create_with_global_object(Bindings::WindowObject& window)
    {
        return XMLHttpRequest::create(window.impl());
    }

    virtual ~XMLHttpRequest() override;

    using RefCounted::ref;
    using RefCounted::unref;

    ReadyState ready_state() const { return m_ready_state; };
    Fetch::Status status() const { return m_status; };
    DOM::ExceptionOr<String> response_text() const;
    DOM::ExceptionOr<JS::Value> response();
    Bindings::XMLHttpRequestResponseType response_type() const { return m_response_type; }

    DOM::ExceptionOr<void> open(String const& method, String const& url);
    DOM::ExceptionOr<void> open(String const& method, String const& url, bool async, String const& username = {}, String const& password = {});
    DOM::ExceptionOr<void> send(Optional<XMLHttpRequestBodyInit> body);

    DOM::ExceptionOr<void> set_request_header(String const& header, String const& value);
    void set_response_type(Bindings::XMLHttpRequestResponseType type) { m_response_type = type; }

    String get_response_header(String const& name) { return m_response_headers.get(name).value_or({}); }
    String get_all_response_headers() const;

    Bindings::CallbackType* onreadystatechange();
    void set_onreadystatechange(Optional<Bindings::CallbackType>);

    DOM::ExceptionOr<void> override_mime_type(String const& mime);

    DOM::ExceptionOr<void> set_timeout(u32 timeout);
    u32 timeout() const;

private:
    virtual void ref_event_target() override { ref(); }
    virtual void unref_event_target() override { unref(); }
    virtual JS::Object* create_wrapper(JS::GlobalObject&) override;

    void set_ready_state(ReadyState);
    void set_status(Fetch::Status status) { m_status = status; }
    void fire_progress_event(String const&, u64, u64);

    MimeSniff::MimeType get_response_mime_type() const;
    Optional<StringView> get_final_encoding() const;
    MimeSniff::MimeType get_final_mime_type() const;

    String get_text_response() const;

    Optional<Vector<String>> get_decode_and_split(String const& header_name, HashMap<String, String, CaseInsensitiveStringTraits> const& header_list) const;
    Optional<MimeSniff::MimeType> extract_mime_type(HashMap<String, String, CaseInsensitiveStringTraits> const& header_list) const;

    explicit XMLHttpRequest(HTML::Window&);

    NonnullRefPtr<HTML::Window> m_window;

    ReadyState m_ready_state { ReadyState::Unsent };
    Fetch::Status m_status { 0 };
    bool m_send { false };
    u32 m_timeout { 0 };

    String m_method;
    AK::URL m_url;

    Bindings::XMLHttpRequestResponseType m_response_type;

    HashMap<String, String, CaseInsensitiveStringTraits> m_request_headers;
    HashMap<String, String, CaseInsensitiveStringTraits> m_response_headers;

    bool m_synchronous { false };
    bool m_upload_complete { false };
    bool m_upload_listener { false };
    bool m_timed_out { false };

    ByteBuffer m_received_bytes;

    enum class Failure {
        /// ????
    };
    Variant<JS::Handle<JS::Value>, Failure, Empty> m_response_object;

    // https://xhr.spec.whatwg.org/#override-mime-type
    Optional<MimeSniff::MimeType> m_override_mime_type;
};

}