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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
#ifndef HEADER_CURL_REQUEST_H
#define HEADER_CURL_REQUEST_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
/* This file is for lib internal stuff */
#include "curl_setup.h"
#include "bufq.h"
/* forward declarations */
struct UserDefined;
#ifndef CURL_DISABLE_DOH
struct doh_probes;
#endif
enum expect100 {
EXP100_SEND_DATA, /* enough waiting, just send the body now */
EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
EXP100_SENDING_REQUEST, /* still sending the request but will wait for
the 100 header once done with the request */
EXP100_FAILED /* used on 417 Expectation Failed */
};
enum upgrade101 {
UPGR101_INIT, /* default state */
UPGR101_WS, /* upgrade to WebSockets requested */
UPGR101_H2, /* upgrade to HTTP/2 requested */
UPGR101_RECEIVED, /* 101 response received */
UPGR101_WORKING /* talking upgraded protocol */
};
/*
* Request specific data in the easy handle (Curl_easy). Previously,
* these members were on the connectdata struct but since a conn struct may
* now be shared between different Curl_easys, we store connection-specific
* data here. This struct only keeps stuff that is interesting for *this*
* request, as it will be cleared between multiple ones
*/
struct SingleRequest {
curl_off_t size; /* -1 if unknown at this point */
curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
-1 means unlimited */
curl_off_t bytecount; /* total number of bytes read */
curl_off_t writebytecount; /* number of bytes written */
struct curltime start; /* transfer started at this time */
unsigned int headerbytecount; /* received server headers (not CONNECT
headers) */
unsigned int allheadercount; /* all received headers (server + CONNECT) */
unsigned int deductheadercount; /* this amount of bytes does not count when
we check if anything has been transferred
at the end of a connection. We use this
counter to make only a 100 reply (without
a following second response code) result
in a CURLE_GOT_NOTHING error code */
int headerline; /* counts header lines to better track the
first one */
curl_off_t offset; /* possible resume offset read from the
Content-Range: header */
int httpversion; /* Version in response (09, 10, 11, etc.) */
int httpcode; /* error code from the 'HTTP/1.? XXX' or
'RTSP/1.? XXX' line */
int keepon;
enum upgrade101 upgr101; /* 101 upgrade state */
/* Client Writer stack, handles transfer- and content-encodings, protocol
* checks, pausing by client callbacks. */
struct Curl_cwriter *writer_stack;
/* Client Reader stack, handles transfer- and content-encodings, protocol
* checks, pausing by client callbacks. */
struct Curl_creader *reader_stack;
struct bufq sendbuf; /* data which needs to be send to the server */
size_t sendbuf_hds_len; /* amount of header bytes in sendbuf */
time_t timeofdoc;
char *location; /* This points to an allocated version of the Location:
header data */
char *newurl; /* Set to the new URL to use when a redirect or a retry is
wanted */
/* Allocated protocol-specific data. Each protocol handler makes sure this
points to data it needs. */
union {
struct FILEPROTO *file;
struct FTP *ftp;
struct IMAP *imap;
struct ldapreqinfo *ldap;
struct MQTT *mqtt;
struct POP3 *pop3;
struct RTSP *rtsp;
struct smb_request *smb;
struct SMTP *smtp;
struct SSHPROTO *ssh;
struct TELNET *telnet;
} p;
#ifndef CURL_DISABLE_DOH
struct doh_probes *doh; /* DoH specific data for this request */
#endif
#ifndef CURL_DISABLE_COOKIES
unsigned char setcookies;
#endif
BIT(header); /* incoming data has HTTP header */
BIT(done); /* request is done, e.g. no more send/recv should
* happen. This can be TRUE before `upload_done` or
* `download_done` is TRUE. */
BIT(content_range); /* set TRUE if Content-Range: was found */
BIT(download_done); /* set to TRUE when download is complete */
BIT(eos_written); /* iff EOS has been written to client */
BIT(eos_read); /* iff EOS has been read from the client */
BIT(eos_sent); /* iff EOS has been sent to the server */
BIT(rewind_read); /* iff reader needs rewind at next start */
BIT(upload_done); /* set to TRUE when all request data has been sent */
BIT(upload_aborted); /* set to TRUE when upload was aborted. Will also
* show `upload_done` as TRUE. */
BIT(ignorebody); /* we read a response-body but we ignore it! */
BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
204 or 304 */
BIT(chunk); /* if set, this is a chunked transfer-encoding */
BIT(resp_trailer); /* response carried 'Trailer:' header field */
BIT(ignore_cl); /* ignore content-length */
BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
on upload */
BIT(getheader); /* TRUE if header parsing is wanted */
BIT(no_body); /* the response has no body */
BIT(authneg); /* TRUE when the auth phase has started, which means
that we are creating a request with an auth header,
but it is not the final request in the auth
negotiation. */
BIT(sendbuf_init); /* sendbuf is initialized */
BIT(shutdown); /* request end will shutdown connection */
#ifdef USE_HYPER
BIT(bodywritten);
#endif
};
/**
* Initialize the state of the request for first use.
*/
void Curl_req_init(struct SingleRequest *req);
/**
* The request is about to start. Record time and do a soft reset.
*/
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data);
/**
* The request may continue with a follow up. Reset
* members, but keep start time for overall duration calc.
*/
CURLcode Curl_req_soft_reset(struct SingleRequest *req,
struct Curl_easy *data);
/**
* The request is done. If not aborted, make sure that buffers are
* flushed to the client.
* @param req the request
* @param data the transfer
* @param aborted TRUE iff the request was aborted/errored
*/
CURLcode Curl_req_done(struct SingleRequest *req,
struct Curl_easy *data, bool aborted);
/**
* Free the state of the request, not usable afterwards.
*/
void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data);
/**
* Hard reset the state of the request to virgin state base on
* transfer settings.
*/
void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data);
#ifndef USE_HYPER
/**
* Send request headers. If not all could be sent
* they will be buffered. Use `Curl_req_flush()` to make sure
* bytes are really send.
* @param data the transfer making the request
* @param buf the complete header bytes, no body
* @return CURLE_OK (on blocking with *pnwritten == 0) or error.
*/
CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *buf);
#endif /* !USE_HYPER */
/**
* TRUE iff the request has sent all request headers and data.
*/
bool Curl_req_done_sending(struct Curl_easy *data);
/*
* Read more from client and flush all buffered request bytes.
* @return CURLE_OK on success or the error on the sending.
* Never returns CURLE_AGAIN.
*/
CURLcode Curl_req_send_more(struct Curl_easy *data);
/**
* TRUE iff the request wants to send, e.g. has buffered bytes.
*/
bool Curl_req_want_send(struct Curl_easy *data);
/**
* TRUE iff the request has no buffered bytes yet to send.
*/
bool Curl_req_sendbuf_empty(struct Curl_easy *data);
/**
* Stop sending any more request data to the server.
* Will clear the send buffer and mark request sending as done.
*/
CURLcode Curl_req_abort_sending(struct Curl_easy *data);
/**
* Stop sending and receiving any more request data.
* Will abort sending if not done.
*/
CURLcode Curl_req_stop_send_recv(struct Curl_easy *data);
/**
* Invoked when all request data has been uploaded.
*/
CURLcode Curl_req_set_upload_done(struct Curl_easy *data);
#endif /* HEADER_CURL_REQUEST_H */
|