mirror of https://github.com/adamdruppe/arsd.git
auto-follow location header support inside single request object
This commit is contained in:
parent
4cf16e9248
commit
1489c4187a
65
http2.d
65
http2.d
|
@ -590,6 +590,10 @@ struct BasicAuth {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
class HttpRequest {
|
class HttpRequest {
|
||||||
|
|
||||||
|
/// Automatically follow a redirection?
|
||||||
|
bool followLocation = false;
|
||||||
|
|
||||||
private static {
|
private static {
|
||||||
// we manage the actual connections. When a request is made on a particular
|
// we manage the actual connections. When a request is made on a particular
|
||||||
// host, we try to reuse connections. We may open more than one connection per
|
// host, we try to reuse connections. We may open more than one connection per
|
||||||
|
@ -627,7 +631,7 @@ class HttpRequest {
|
||||||
socket = new Socket(AddressFamily.INET, SocketType.STREAM);
|
socket = new Socket(AddressFamily.INET, SocketType.STREAM);
|
||||||
|
|
||||||
socket.connect(new InternetAddress(host, port));
|
socket.connect(new InternetAddress(host, port));
|
||||||
debug(arsd_http2) writeln("opening to ", host, ":", port);
|
debug(arsd_http2) writeln("opening to ", host, ":", port, " ", cast(void*) socket);
|
||||||
assert(socket.handle() !is socket_t.init);
|
assert(socket.handle() !is socket_t.init);
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
@ -774,10 +778,12 @@ class HttpRequest {
|
||||||
loseSocket(request.requestParameters.host, request.requestParameters.port, request.requestParameters.ssl, sock);
|
loseSocket(request.requestParameters.host, request.requestParameters.port, request.requestParameters.ssl, sock);
|
||||||
} else {
|
} else {
|
||||||
// data available
|
// data available
|
||||||
request.handleIncomingData(buffer[0 .. got]);
|
auto stillAlive = request.handleIncomingData(buffer[0 .. got]);
|
||||||
|
|
||||||
if(request.state == HttpRequest.State.complete || request.state == HttpRequest.State.aborted) {
|
if(!stillAlive || request.state == HttpRequest.State.complete || request.state == HttpRequest.State.aborted) {
|
||||||
|
//import std.stdio; writeln(cast(void*) sock, " ", stillAlive, " ", request.state);
|
||||||
inactive[inactiveCount++] = sock;
|
inactive[inactiveCount++] = sock;
|
||||||
|
continue;
|
||||||
// reuse the socket for another pending request, if we can
|
// reuse the socket for another pending request, if we can
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -799,16 +805,18 @@ class HttpRequest {
|
||||||
if(writeSet.isSet(sock)) {
|
if(writeSet.isSet(sock)) {
|
||||||
assert(request.sendBuffer.length);
|
assert(request.sendBuffer.length);
|
||||||
auto sent = sock.send(request.sendBuffer);
|
auto sent = sock.send(request.sendBuffer);
|
||||||
debug(arsd_http2_verbose) writeln(cast(string) request.sendBuffer);
|
debug(arsd_http2_verbose) writeln(cast(void*) sock, "<send>", cast(string) request.sendBuffer, "</send>");
|
||||||
if(sent <= 0)
|
if(sent <= 0)
|
||||||
throw new Exception("send error " ~ lastSocketError);
|
throw new Exception("send error " ~ lastSocketError);
|
||||||
request.sendBuffer = request.sendBuffer[sent .. $];
|
request.sendBuffer = request.sendBuffer[sent .. $];
|
||||||
|
if(request.sendBuffer.length == 0) {
|
||||||
request.state = State.waitingForResponse;
|
request.state = State.waitingForResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach(s; inactive[0 .. inactiveCount]) {
|
foreach(s; inactive[0 .. inactiveCount]) {
|
||||||
debug(arsd_http2) writeln("removing socket from active list");
|
debug(arsd_http2) writeln("removing socket from active list ", cast(void*) s);
|
||||||
activeRequestOnSocket.remove(s);
|
activeRequestOnSocket.remove(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,7 +861,8 @@ class HttpRequest {
|
||||||
|
|
||||||
const(ubyte)[] leftoverDataFromLastTime;
|
const(ubyte)[] leftoverDataFromLastTime;
|
||||||
|
|
||||||
void handleIncomingData(scope const ubyte[] dataIn) {
|
bool handleIncomingData(scope const ubyte[] dataIn) {
|
||||||
|
bool stillAlive = true;
|
||||||
debug(arsd_http2) writeln("handleIncomingData, state: ", state);
|
debug(arsd_http2) writeln("handleIncomingData, state: ", state);
|
||||||
if(state == State.waitingForResponse) {
|
if(state == State.waitingForResponse) {
|
||||||
state = State.readingHeaders;
|
state = State.readingHeaders;
|
||||||
|
@ -1119,6 +1128,19 @@ class HttpRequest {
|
||||||
responseData.content = cast(ubyte[]) n;
|
responseData.content = cast(ubyte[]) n;
|
||||||
//responseData.content ~= cast(ubyte[]) uncompress.flush();
|
//responseData.content ~= cast(ubyte[]) uncompress.flush();
|
||||||
}
|
}
|
||||||
|
if(followLocation && responseData.location.length) {
|
||||||
|
static bool first = true;
|
||||||
|
if(!first) asm { int 3; }
|
||||||
|
populateFromInfo(Uri(responseData.location), HttpVerb.GET);
|
||||||
|
import std.stdio; writeln("redirected to ", responseData.location);
|
||||||
|
first = false;
|
||||||
|
responseData = HttpResponse.init;
|
||||||
|
headerReadingState = HeaderReadingState.init;
|
||||||
|
bodyReadingState = BodyReadingState.init;
|
||||||
|
state = State.unsent;
|
||||||
|
stillAlive = false;
|
||||||
|
sendPrivate(false);
|
||||||
|
} else {
|
||||||
state = State.complete;
|
state = State.complete;
|
||||||
responseData.contentText = cast(string) responseData.content;
|
responseData.contentText = cast(string) responseData.content;
|
||||||
// FIXME
|
// FIXME
|
||||||
|
@ -1127,11 +1149,14 @@ class HttpRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(data.length)
|
if(data.length)
|
||||||
leftoverDataFromLastTime = data.dup;
|
leftoverDataFromLastTime = data.dup;
|
||||||
else
|
else
|
||||||
leftoverDataFromLastTime = null;
|
leftoverDataFromLastTime = null;
|
||||||
|
|
||||||
|
return stillAlive;
|
||||||
}
|
}
|
||||||
|
|
||||||
this() {
|
this() {
|
||||||
|
@ -1139,7 +1164,15 @@ class HttpRequest {
|
||||||
|
|
||||||
///
|
///
|
||||||
this(Uri where, HttpVerb method) {
|
this(Uri where, HttpVerb method) {
|
||||||
|
populateFromInfo(where, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Final url after any redirections
|
||||||
|
string finalUrl;
|
||||||
|
|
||||||
|
void populateFromInfo(Uri where, HttpVerb method) {
|
||||||
auto parts = where;
|
auto parts = where;
|
||||||
|
finalUrl = where.toString();
|
||||||
requestParameters.method = method;
|
requestParameters.method = method;
|
||||||
requestParameters.host = parts.host;
|
requestParameters.host = parts.host;
|
||||||
requestParameters.port = cast(ushort) parts.port;
|
requestParameters.port = cast(ushort) parts.port;
|
||||||
|
@ -1211,6 +1244,10 @@ class HttpRequest {
|
||||||
|
|
||||||
/// Sends the request asynchronously.
|
/// Sends the request asynchronously.
|
||||||
void send() {
|
void send() {
|
||||||
|
sendPrivate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendPrivate(bool advance) {
|
||||||
if(state != State.unsent && state != State.aborted)
|
if(state != State.unsent && state != State.aborted)
|
||||||
return; // already sent
|
return; // already sent
|
||||||
string headers;
|
string headers;
|
||||||
|
@ -1239,14 +1276,25 @@ class HttpRequest {
|
||||||
|
|
||||||
sendBuffer = cast(ubyte[]) headers ~ requestParameters.bodyData;
|
sendBuffer = cast(ubyte[]) headers ~ requestParameters.bodyData;
|
||||||
|
|
||||||
|
// import std.stdio; writeln("******* ", sendBuffer);
|
||||||
|
|
||||||
responseData = HttpResponse.init;
|
responseData = HttpResponse.init;
|
||||||
responseData.requestParameters = requestParameters;
|
responseData.requestParameters = requestParameters;
|
||||||
bodyBytesSent = 0;
|
bodyBytesSent = 0;
|
||||||
bodyBytesReceived = 0;
|
bodyBytesReceived = 0;
|
||||||
state = State.pendingAvailableConnection;
|
state = State.pendingAvailableConnection;
|
||||||
|
|
||||||
|
bool alreadyPending = false;
|
||||||
|
foreach(req; pending)
|
||||||
|
if(req is this) {
|
||||||
|
alreadyPending = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!alreadyPending) {
|
||||||
pending ~= this;
|
pending ~= this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(advance)
|
||||||
HttpRequest.advanceConnections();
|
HttpRequest.advanceConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,9 +1393,6 @@ class HttpClient {
|
||||||
bool useHttp11 = true; ///
|
bool useHttp11 = true; ///
|
||||||
bool acceptGzip = true; ///
|
bool acceptGzip = true; ///
|
||||||
|
|
||||||
/// Automatically follow a redirection?
|
|
||||||
bool followLocation = false; /// NOT IMPLEMENTED
|
|
||||||
|
|
||||||
///
|
///
|
||||||
@property Uri location() {
|
@property Uri location() {
|
||||||
return currentUrl;
|
return currentUrl;
|
||||||
|
@ -1362,6 +1407,8 @@ class HttpClient {
|
||||||
currentDomain = where.host;
|
currentDomain = where.host;
|
||||||
auto request = new HttpRequest(currentUrl, method);
|
auto request = new HttpRequest(currentUrl, method);
|
||||||
|
|
||||||
|
request.followLocation = true;
|
||||||
|
|
||||||
request.requestParameters.userAgent = userAgent;
|
request.requestParameters.userAgent = userAgent;
|
||||||
request.requestParameters.authorization = authorization;
|
request.requestParameters.authorization = authorization;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue