Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
arduino-esp32
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
arduino-esp32
Commits
ee88c42c
Unverified
Commit
ee88c42c
authored
Oct 01, 2020
by
Clickau
Committed by
GitHub
Oct 01, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for following redirects in HTTPClient (#4240)
parent
837cc3d2
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
172 additions
and
17 deletions
+172
-17
libraries/HTTPClient/src/HTTPClient.cpp
libraries/HTTPClient/src/HTTPClient.cpp
+145
-17
libraries/HTTPClient/src/HTTPClient.h
libraries/HTTPClient/src/HTTPClient.h
+27
-0
No files found.
libraries/HTTPClient/src/HTTPClient.cpp
View file @
ee88c42c
...
@@ -548,29 +548,106 @@ int HTTPClient::sendRequest(const char * type, String payload)
...
@@ -548,29 +548,106 @@ int HTTPClient::sendRequest(const char * type, String payload)
*/
*/
int
HTTPClient
::
sendRequest
(
const
char
*
type
,
uint8_t
*
payload
,
size_t
size
)
int
HTTPClient
::
sendRequest
(
const
char
*
type
,
uint8_t
*
payload
,
size_t
size
)
{
{
// connect to server
int
code
;
if
(
!
connect
())
{
bool
redirect
=
false
;
return
returnError
(
HTTPC_ERROR_CONNECTION_REFUSED
);
uint16_t
redirectCount
=
0
;
}
do
{
// wipe out any existing headers from previous request
for
(
size_t
i
=
0
;
i
<
_headerKeysCount
;
i
++
)
{
if
(
_currentHeaders
[
i
].
value
.
length
()
>
0
)
{
_currentHeaders
[
i
].
value
.
clear
();
}
}
if
(
payload
&&
size
>
0
)
{
log_d
(
"request type: '%s' redirCount: %d
\n
"
,
type
,
redirectCount
);
addHeader
(
F
(
"Content-Length"
),
String
(
size
));
}
// connect to server
if
(
!
connect
())
{
return
returnError
(
HTTPC_ERROR_CONNECTION_REFUSED
);
}
// send Header
if
(
payload
&&
size
>
0
)
{
if
(
!
sendHeader
(
type
))
{
addHeader
(
F
(
"Content-Length"
),
String
(
size
));
return
returnError
(
HTTPC_ERROR_SEND_HEADER_FAILED
);
}
}
// send Payload if needed
// send Header
if
(
payload
&&
size
>
0
)
{
if
(
!
sendHeader
(
type
))
{
if
(
_client
->
write
(
&
payload
[
0
],
size
)
!=
size
)
{
return
returnError
(
HTTPC_ERROR_SEND_HEADER_FAILED
);
return
returnError
(
HTTPC_ERROR_SEND_PAYLOAD_FAILED
);
}
// send Payload if needed
if
(
payload
&&
size
>
0
)
{
if
(
_client
->
write
(
&
payload
[
0
],
size
)
!=
size
)
{
return
returnError
(
HTTPC_ERROR_SEND_PAYLOAD_FAILED
);
}
}
code
=
handleHeaderResponse
();
Serial
.
printf
(
"sendRequest code=%d
\n
"
,
code
);
// Handle redirections as stated in RFC document:
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
//
// Implementing HTTP_CODE_FOUND as redirection with GET method,
// to follow most of existing user agent implementations.
//
redirect
=
false
;
if
(
_followRedirects
!=
HTTPC_DISABLE_FOLLOW_REDIRECTS
&&
redirectCount
<
_redirectLimit
&&
_location
.
length
()
>
0
)
{
switch
(
code
)
{
// redirecting using the same method
case
HTTP_CODE_MOVED_PERMANENTLY
:
case
HTTP_CODE_TEMPORARY_REDIRECT
:
{
if
(
// allow to force redirections on other methods
// (the RFC require user to accept the redirection)
_followRedirects
==
HTTPC_FORCE_FOLLOW_REDIRECTS
||
// allow GET and HEAD methods without force
!
strcmp
(
type
,
"GET"
)
||
!
strcmp
(
type
,
"HEAD"
)
)
{
redirectCount
+=
1
;
log_d
(
"following redirect (the same method): '%s' redirCount: %d
\n
"
,
_location
.
c_str
(),
redirectCount
);
if
(
!
setURL
(
_location
))
{
log_d
(
"failed setting URL for redirection
\n
"
);
// no redirection
break
;
}
// redirect using the same request method and payload, diffrent URL
redirect
=
true
;
}
break
;
}
// redirecting with method dropped to GET or HEAD
// note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method
case
HTTP_CODE_FOUND
:
case
HTTP_CODE_SEE_OTHER
:
{
redirectCount
+=
1
;
log_d
(
"following redirect (dropped to GET/HEAD): '%s' redirCount: %d
\n
"
,
_location
.
c_str
(),
redirectCount
);
if
(
!
setURL
(
_location
))
{
log_d
(
"failed setting URL for redirection
\n
"
);
// no redirection
break
;
}
// redirect after changing method to GET/HEAD and dropping payload
type
=
"GET"
;
payload
=
nullptr
;
size
=
0
;
redirect
=
true
;
break
;
}
default:
break
;
}
}
}
}
}
while
(
redirect
);
// handle Server Response (Header)
// handle Server Response (Header)
return
returnError
(
handleHeaderResponse
()
);
return
returnError
(
code
);
}
}
/**
/**
...
@@ -1143,6 +1220,10 @@ int HTTPClient::handleHeaderResponse()
...
@@ -1143,6 +1220,10 @@ int HTTPClient::handleHeaderResponse()
transferEncoding
=
headerValue
;
transferEncoding
=
headerValue
;
}
}
if
(
headerName
.
equalsIgnoreCase
(
"Location"
))
{
_location
=
headerValue
;
}
for
(
size_t
i
=
0
;
i
<
_headerKeysCount
;
i
++
)
{
for
(
size_t
i
=
0
;
i
<
_headerKeysCount
;
i
++
)
{
if
(
_currentHeaders
[
i
].
key
.
equalsIgnoreCase
(
headerName
))
{
if
(
_currentHeaders
[
i
].
key
.
equalsIgnoreCase
(
headerName
))
{
_currentHeaders
[
i
].
value
=
headerValue
;
_currentHeaders
[
i
].
value
=
headerValue
;
...
@@ -1320,3 +1401,50 @@ int HTTPClient::returnError(int error)
...
@@ -1320,3 +1401,50 @@ int HTTPClient::returnError(int error)
}
}
return
error
;
return
error
;
}
}
void
HTTPClient
::
setFollowRedirects
(
followRedirects_t
follow
)
{
_followRedirects
=
follow
;
}
void
HTTPClient
::
setRedirectLimit
(
uint16_t
limit
)
{
_redirectLimit
=
limit
;
}
/**
* set the URL to a new value. Handy for following redirects.
* @param url
*/
bool
HTTPClient
::
setURL
(
const
String
&
url
)
{
// if the new location is only a path then only update the URI
if
(
url
&&
url
[
0
]
==
'/'
)
{
_uri
=
url
;
clear
();
return
true
;
}
if
(
!
url
.
startsWith
(
_protocol
+
':'
))
{
log_d
(
"new URL not the same protocol, expected '%s', URL: '%s'
\n
"
,
_protocol
.
c_str
(),
url
.
c_str
());
return
false
;
}
// check if the port is specified
int
indexPort
=
url
.
indexOf
(
':'
,
6
);
// find the first ':' excluding the one from the protocol
int
indexURI
=
url
.
indexOf
(
'/'
,
7
);
// find where the URI starts to make sure the ':' is not part of it
if
(
indexPort
==
-
1
||
indexPort
>
indexURI
)
{
// the port is not specified
_port
=
(
_protocol
==
"https"
?
443
:
80
);
}
// disconnect but preserve _client (clear _canReuse so disconnect will close the connection)
_canReuse
=
false
;
disconnect
(
true
);
return
beginInternal
(
url
,
_protocol
.
c_str
());
}
const
String
&
HTTPClient
::
getLocation
(
void
)
{
return
_location
;
}
\ No newline at end of file
libraries/HTTPClient/src/HTTPClient.h
View file @
ee88c42c
...
@@ -119,6 +119,24 @@ typedef enum {
...
@@ -119,6 +119,24 @@ typedef enum {
HTTPC_TE_CHUNKED
HTTPC_TE_CHUNKED
}
transferEncoding_t
;
}
transferEncoding_t
;
/**
* redirection follow mode.
* + `HTTPC_DISABLE_FOLLOW_REDIRECTS` - no redirection will be followed.
* + `HTTPC_STRICT_FOLLOW_REDIRECTS` - strict RFC2616, only requests using
* GET or HEAD methods will be redirected (using the same method),
* since the RFC requires end-user confirmation in other cases.
* + `HTTPC_FORCE_FOLLOW_REDIRECTS` - all redirections will be followed,
* regardless of a used method. New request will use the same method,
* and they will include the same body data and the same headers.
* In the sense of the RFC, it's just like every redirection is confirmed.
*/
typedef
enum
{
HTTPC_DISABLE_FOLLOW_REDIRECTS
,
HTTPC_STRICT_FOLLOW_REDIRECTS
,
HTTPC_FORCE_FOLLOW_REDIRECTS
}
followRedirects_t
;
#ifdef HTTPCLIENT_1_1_COMPATIBLE
#ifdef HTTPCLIENT_1_1_COMPATIBLE
class
TransportTraits
;
class
TransportTraits
;
typedef
std
::
unique_ptr
<
TransportTraits
>
TransportTraitsPtr
;
typedef
std
::
unique_ptr
<
TransportTraits
>
TransportTraitsPtr
;
...
@@ -156,6 +174,11 @@ public:
...
@@ -156,6 +174,11 @@ public:
void
setConnectTimeout
(
int32_t
connectTimeout
);
void
setConnectTimeout
(
int32_t
connectTimeout
);
void
setTimeout
(
uint16_t
timeout
);
void
setTimeout
(
uint16_t
timeout
);
// Redirections
void
setFollowRedirects
(
followRedirects_t
follow
);
void
setRedirectLimit
(
uint16_t
limit
);
// max redirects to follow for a single request
bool
setURL
(
const
String
&
url
);
void
useHTTP10
(
bool
usehttp10
=
true
);
void
useHTTP10
(
bool
usehttp10
=
true
);
/// request handling
/// request handling
...
@@ -182,6 +205,7 @@ public:
...
@@ -182,6 +205,7 @@ public:
int
getSize
(
void
);
int
getSize
(
void
);
const
String
&
getLocation
(
void
);
WiFiClient
&
getStream
(
void
);
WiFiClient
&
getStream
(
void
);
WiFiClient
*
getStreamPtr
(
void
);
WiFiClient
*
getStreamPtr
(
void
);
...
@@ -235,6 +259,9 @@ protected:
...
@@ -235,6 +259,9 @@ protected:
int
_returnCode
=
0
;
int
_returnCode
=
0
;
int
_size
=
-
1
;
int
_size
=
-
1
;
bool
_canReuse
=
false
;
bool
_canReuse
=
false
;
followRedirects_t
_followRedirects
=
HTTPC_DISABLE_FOLLOW_REDIRECTS
;
uint16_t
_redirectLimit
=
10
;
String
_location
;
transferEncoding_t
_transferEncoding
=
HTTPC_TE_IDENTITY
;
transferEncoding_t
_transferEncoding
=
HTTPC_TE_IDENTITY
;
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment