I am submitting a CURL Post request to an API which, upon success, returns status "201 Created" with the URL of the resource in the LOCATION
part of the header. What I'd like is to automatically retrieve the newly created resource but so far haven't been able to do so. I've tried setting curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
but to no avail. it's worth noting that the resource does require a GET
request.
I'm not sure if it's the status code being a 201, or if the request method needs to change from POST
to GET
, but for some reason it's not following the LOCATION
header. Fetching curl_getinfo($ch,CURLINFO_EFFECTIVE_URL);
seems to confirm this as the result is the same as the original URL, not the new LOCATION
.
As a last resort I have considered simply parsing the headers and creating a new CURL request, but this would not be optimal and I'm guessing that I'm just missing something simple to make this work as desired.
How can I get CURL to automatically follow and submit a GET
request to the LOCATION
returned with a 201 response?
You can't.
With curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl follow the response LOCATION
only for 3xx
status codes.
AFAIK and stating as the documentation there is no way to force curl to follow-location with a 201 response.
You have to parse the header, fetch the LOCATION and then issue a second curl request.
Following a location with a status different than 3xx
would be an anomaly. Also from the curl command line tool and C library documentation: -L, --location -- (HTTP) If the server reports that the requested page has moved to a different location (indicated with a Location: header and a 3XX response code), this option will make curl redo the request on the new place
Giving a quick look at the curl source code you find on /lib/http.c
the function Curl_http_readwrite_headers
.
Location follow is handled inside with this conditional:
else if((k->httpcode >= 300 && k->httpcode < 400) &&
checkprefix("Location:", k->p) &&
!data->req.location) {
/* this is the URL that the server advises us to use instead */
char *location = Curl_copy_header_value(k->p);
if(!location)
return CURLE_OUT_OF_MEMORY;
if(!*location)
/* ignore empty data */
free(location);
else {
data->req.location = location;
if(data->set.http_follow_location) {
DEBUGASSERT(!data->req.newurl);
data->req.newurl = strdup(data->req.location); /* clone */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
/* some cases of POST and PUT etc needs to rewind the data
stream at this point */
result = http_perhapsrewind(conn);
if(result)
return result;
}
}
}
The location is followed with a status code between 300
and 399
I understand this doesn't answer your question in the pure sense of it -- my solution isn't even in PHP, but here's a way (using jq) to follow a 201 with cURL:
shrinkImageFunction() {
echo
echo Compressing $1 . . .
curl --user api: https://tinypng.com/developers \
--data-binary @$1 \
-o .$1-json \
-s \
https://api.tinify.com/shrink
cat .$1-json | jq -r '.output.url' > .$1-url
url=$(cat .$1-url)
if [ -z "$url" ]; then
echo Something went wrong
return
fi
echo Downloading $url . . .
echo
curl -o compressed-$1 $url
echo
rm .$1-json
rm .$1-url
}
# alias for using tinypng
alias shrinkImage=shrinkImageFunction
I threw this together today while doing similar research and figured I'd share having come across this question while looking for options.
It could easily be tweaked to parse the http 201 header response using sed or similar instead of jq where I'm parsing the http body json response provided by tinypng (used merely for reference -- I'm not affiliated with them).