This repository has been archived by the owner on Jul 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 632
/
Copy pathResponseHandler.cs
155 lines (128 loc) · 5.27 KB
/
ResponseHandler.cs
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
using System;
using System.Net;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Network.WinAuth.Security;
namespace Titanium.Web.Proxy;
/// <summary>
/// Handle the response from server.
/// </summary>
public partial class ProxyServer
{
/// <summary>
/// Called asynchronously when a request was successful and we received the response.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <returns> The task.</returns>
private async Task HandleHttpSessionResponse(SessionEventArgs args)
{
var cancellationToken = args.CancellationTokenSource.Token;
// read response & headers from server
await args.HttpClient.ReceiveResponse(cancellationToken);
// Server may send expect-continue even if not asked for it in request.
// According to spec "the client can simply discard this interim response."
if (args.HttpClient.Response.StatusCode == (int)HttpStatusCode.Continue)
{
await args.ClearResponse(cancellationToken);
await args.HttpClient.ReceiveResponse(cancellationToken);
}
args.TimeLine["Response Received"] = DateTime.UtcNow;
var response = args.HttpClient.Response;
args.ReRequest = false;
// check for windows authentication
if (args.EnableWinAuth)
{
if (response.StatusCode == (int)HttpStatusCode.Unauthorized)
await Handle401UnAuthorized(args);
else
WinAuthEndPoint.AuthenticatedResponse(args.HttpClient.Data);
}
// save original values so that if user changes them
// we can still use original values when syphoning out data from attached tcp connection.
response.SetOriginalHeaders();
// if user requested call back then do it
if (!response.Locked) await OnBeforeResponse(args);
// it may changed in the user event
response = args.HttpClient.Response;
var clientStream = args.ClientStream;
// user set custom response by ignoring original response from server.
if (response.Locked)
{
// write custom user response with body and return.
await clientStream.WriteResponseAsync(response, cancellationToken);
if (args.HttpClient.HasConnection && !args.HttpClient.CloseServerConnection)
// syphon out the original response body from server connection
// so that connection will be good to be reused.
await args.SyphonOutBodyAsync(false, cancellationToken);
return;
}
// if user requested to send request again
// likely after making modifications from User Response Handler
if (args.ReRequest)
{
if (args.HttpClient.HasConnection) await TcpConnectionFactory.Release(args.HttpClient.Connection);
// clear current response
await args.ClearResponse(cancellationToken);
var result = await HandleHttpSessionRequest(args, null, args.ClientConnection.NegotiatedApplicationProtocol,
cancellationToken, args.CancellationTokenSource);
if (result.LatestConnection != null) args.HttpClient.SetConnection(result.LatestConnection);
return;
}
response.Locked = true;
if (!args.IsTransparent && !args.IsSocks) response.Headers.FixProxyHeaders();
await clientStream.WriteResponseAsync(response, cancellationToken);
if (response.OriginalHasBody)
{
if (response.IsBodySent)
{
// syphon out body
await args.SyphonOutBodyAsync(false, cancellationToken);
}
else
{
// Copy body if exists
var serverStream = args.HttpClient.Connection.Stream;
await serverStream.CopyBodyAsync(response, false, clientStream, TransformationMode.None,
false, args, cancellationToken);
}
response.IsBodyReceived = true;
}
args.TimeLine["Response Sent"] = DateTime.UtcNow;
}
/// <summary>
/// Invoke before response if it is set.
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private async Task OnBeforeResponse(SessionEventArgs args)
{
if (BeforeResponse != null) await BeforeResponse.InvokeAsync(this, args, ExceptionFunc);
}
/// <summary>
/// Invoke after response if it is set.
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private async Task OnAfterResponse(SessionEventArgs args)
{
if (AfterResponse != null) await AfterResponse.InvokeAsync(this, args, ExceptionFunc);
}
#if DEBUG
internal bool ShouldCallBeforeResponseBodyWrite()
{
if (OnResponseBodyWrite != null)
{
return true;
}
return false;
}
internal async Task OnBeforeResponseBodyWrite(BeforeBodyWriteEventArgs args)
{
if (OnResponseBodyWrite != null)
{
await OnResponseBodyWrite.InvokeAsync(this, args, ExceptionFunc);
}
}
#endif
}