-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRequestBuilder.cs
More file actions
164 lines (134 loc) · 5.95 KB
/
Copy pathRequestBuilder.cs
File metadata and controls
164 lines (134 loc) · 5.95 KB
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
using System.Net.Sockets;
using System.Text;
namespace HttpParser;
public static class RequestBuilder
{
private static readonly string _boundary = "----WebKitFormBoundary" + DateTime.Now.Ticks.ToString("x");
public static string SendRequest(HttpRequest request)
{
using (var client = new TcpClient())
{
client.Connect(request.Host, request.Port);
using (var stream = client.GetStream())
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream) { AutoFlush = true })
{
// Строим полный путь с параметрами
var fullPath = BuildPathWithQuery(request);
// Строим тело запроса и определяем Content-Type
var (requestBody, contentType) = BuildRequestBody(request);
// Собираем полный запрос
var httpRequest = BuildHttpRequest(request, fullPath, requestBody, contentType);
// Отправляем
writer.Write(httpRequest);
// Читаем ответ
var response = reader.ReadToEnd();
return response;
}
}
}
private static string BuildPathWithQuery(HttpRequest request)
{
var path = request.Path;
if (request.QueryParameters.Any())
{
var queryString = string.Join("&",
request.QueryParameters.Select(kvp =>
$"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"));
path += "?" + queryString;
}
return path;
}
private static (string body, string contentType) BuildRequestBody(HttpRequest request)
{
// Если есть явно заданное тело - в данном случае такого не бывает
if (!string.IsNullOrEmpty(request.Body))
{
var contentType = request.UseJson ? "application/json" : "text/plain";
return (request.Body, contentType);
}
// Multipart/form-data (формы с файлами)
if (request.UseMultipartFormData && (request.FormData.Any() || request.Files.Any()))
{
return (BuildMultipartFormData(request), $"multipart/form-data; boundary={_boundary}");
}
// application/x-www-form-urlencoded (простые формы)
if (request.UseFormData && request.FormData.Any())
{
var formBody = string.Join("&",
request.FormData.Select(kvp =>
$"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"));
return (formBody, "application/x-www-form-urlencoded");
}
// Пустое тело для GET
return (string.Empty, "application/x-www-form-urlencoded");
}
private static string BuildMultipartFormData(HttpRequest request)
{
var bodyBuilder = new StringBuilder();
// Добавляем обычные поля формы
foreach (var field in request.FormData)
{
bodyBuilder.AppendLine($"--{_boundary}");
bodyBuilder.AppendLine($"Content-Disposition: form-data; name=\"{field.Key}\"");
bodyBuilder.AppendLine();
bodyBuilder.AppendLine(field.Value);
}
// Добавляем файлы
foreach (var file in request.Files)
{
bodyBuilder.AppendLine($"--{_boundary}");
bodyBuilder.AppendLine($"Content-Disposition: form-data; name=\"{file.FieldName}\"; filename=\"{file.FileName}\"");
bodyBuilder.AppendLine($"Content-Type: {file.ContentType}");
bodyBuilder.AppendLine();
Encoding utf8NoBom = new UTF8Encoding(false);
bodyBuilder.AppendLine(utf8NoBom.GetString(file.Content));
}
bodyBuilder.AppendLine($"--{_boundary}--");
return bodyBuilder.ToString();
}
private static string BuildHttpRequest(HttpRequest request, string fullPath, string body, string contentType)
{
var requestBuilder = new StringBuilder();
// Стартовая строка
requestBuilder.AppendLine($"{request.Method.ToUpper()} {fullPath} {request.Protocol}");
// Обязательные заголовки
requestBuilder.AppendLine($"Host: {request.Host}");
// Cookie
if (request.Cookies.Any())
{
var cookies = string.Join("; ",
request.Cookies.Select(kvp => $"{kvp.Key}={kvp.Value}"));
requestBuilder.AppendLine($"Cookie: {cookies}");
}
// Content-Type (если есть тело)
if (!string.IsNullOrEmpty(contentType))
{
requestBuilder.AppendLine($"Content-Type: {contentType}");
}
// Content-Length (если есть тело)
if (!string.IsNullOrEmpty(body))
{
Encoding utf8NoBom = new UTF8Encoding(false);
var contentLength = utf8NoBom.GetByteCount(body);
requestBuilder.AppendLine($"Content-Length: {contentLength}");
}
else
{
requestBuilder.AppendLine($"Content-Length: {0}");
}
// Пользовательские заголовки
foreach (var header in request.Headers)
{
requestBuilder.AppendLine($"{header.Key}: {header.Value}");
}
// Пустая строка - конец заголовков
requestBuilder.AppendLine();
// Тело запроса
if (!string.IsNullOrEmpty(body))
{
requestBuilder.Append(body);
}
return requestBuilder.ToString();
}
}