c#使用Socket发送HTTP/HTTPS请求的实现代码
程序员文章站
2023-12-10 17:20:34
c# 自带的httpwebrequest效率太低,对于自组http封包不好操作。
在写超级sql注入工具时,研究了很长一段时间如何使用socket来发送http、http...
c# 自带的httpwebrequest效率太低,对于自组http封包不好操作。
在写超级sql注入工具时,研究了很长一段时间如何使用socket来发送http、https请求。
经过一年的修改和测试,可完美、高效发送并解析http/https请求。修改过无数次bug。
在这里把核心代码分享出来,供大家学习或做开发参考。
用这个代码写了一个简单的http发包工具。供大家参考。
工具下载:
核心类:http.cs
using system; using system.collections.generic; using system.text; using tools; using system.net; using system.net.sockets; using system.io.compression; using system.io; using system.net.security; using system.text.regularexpressions; using system.threading; using system.diagnostics; using system.security.authentication; using system.security.cryptography.x509certificates; using httptool; namespace tools { public class http { public const char t = ' '; public const string ct = " "; public const string ctrl = " "; public const string content_length_str = "content-length: "; public const string content_length_str_m = "content-length: "; public const string content_length = "content-length"; public const string content_encoding = "content-encoding"; public const string transfer_encoding = "transfer-encoding"; public const string connection = "connection"; public static main main = null; public static long index = 0; public void initmain(main m) { main = m; } /** * 发生异常尝试重连 * */ public static serverinfo sendrequestretry(boolean isssl, int trycount, string host, int port, string payload, string request, int timeout, string encoding, boolean foward_302) { int count = 0; interlocked.increment(ref index); serverinfo server = new serverinfo(); timeout = timeout * 1000; while (true) { if (count >= trycount) break; try { if (!isssl) { server = sendhttprequest(count, host, port, payload, request, timeout, encoding, foward_302); return server; } else { server = sendhttpsrequest(count, host, port, payload, request, timeout, encoding, foward_302); return server; } } catch (exception e) { tools.syslog("发包发生异常,正在重试----" + e.message); server.timeout = true; continue; } finally { count++; } } return server; } private static void checkcontentlength(ref serverinfo server, ref string request) { //重新计算并设置content-length int sindex = request.indexof(ctrl); server.reuqestheader = request; if (sindex != -1) { server.reuqestheader = request.substring(0, sindex); server.reuqestbody = request.substring(sindex + 4, request.length - sindex - 4); int contentlength = encoding.utf8.getbytes(server.reuqestbody).length; string newcontentlength = content_length_str_m + contentlength; if (request.indexof(content_length_str_m) != -1) { request = regex.replace(request, content_length_str_m + "d+", newcontentlength); } else { request = request.insert(sindex, " " + newcontentlength); } } else { request = regex.replace(request, content_length_str + "d+", content_length_str_m + "0"); request += ctrl; } } private static void doheader(ref serverinfo server, ref string[] headers) { for (int i = 0; i < headers.length; i++) { if (i == 0) { server.code = tools.converttoint(headers[i].split(' ')[1]); } else { string[] kv = regex.split(headers[i], ": "); string key = kv[0].tolower(); if (!server.headers.containskey(key)) { //自动识别编码 if ("content-type".equals(key)) { string hecnode = gethtmlencoding(kv[1], ""); if (!string.isnullorempty(hecnode)) { server.encoding = hecnode; } } if (kv.length > 1) { server.headers.add(key, kv[1]); } else { server.headers.add(key, ""); } } } } } private static serverinfo sendhttprequest(int count, string host, int port, string payload, string request, int timeout, string encoding, boolean foward_302) { string index = thread.currentthread.name + http.index; stopwatch sw = new stopwatch(); sw.start(); serverinfo server = new serverinfo(); tcpclient clientsocket = null; int sum = 0; try { if (port > 0 && port <= 65556) { //编码处理 server.request = request; timeoutsocket tos = new timeoutsocket(); clientsocket = tos.connect(host, port, timeout); if (sw.elapsedmilliseconds >= timeout) { return server; } clientsocket.sendtimeout = timeout - tos.usetime; if (clientsocket.connected) { checkcontentlength(ref server, ref request); server.request = request; byte[] requestbyte = encoding.utf8.getbytes(request); clientsocket.client.send(requestbyte); byte[] responsebody = new byte[1024 * 1000]; int len = 0; //获取header头 string tmp = ""; stringbuilder sb = new stringbuilder(); clientsocket.receivetimeout = timeout - (int)sw.elapsedmilliseconds; do { byte[] responseheader = new byte[1]; len = clientsocket.client.receive(responseheader, 1, socketflags.none); if (len == 1) { char c = (char)responseheader[0]; sb.append(c); if (c.equals(t)) { tmp = string.concat(sb[sb.length - 4], sb[sb.length - 3], sb[sb.length - 2], c); } } } while (!tmp.equals(ctrl) && sw.elapsedmilliseconds < timeout); server.header = sb.tostring().replace(ctrl, ""); string[] headers = regex.split(server.header, ct); if (headers != null && headers.length > 0) { //处理header doheader(ref server, ref headers); //自动修正编码 if (!string.isnullorempty(server.encoding)) { encoding = server.encoding; } encoding encod = encoding.getencoding(encoding); //302 301跳转 if ((server.code == 302 || server.code == 301) && foward_302) { stringbuilder rsb = new stringbuilder(server.request); int urlstart = server.request.indexof(" ") + 1; int urlend = server.request.indexof(" http"); if (urlstart != -1 && urlend != -1) { string url = server.request.substring(urlstart, urlend - urlstart); rsb.remove(urlstart, url.length); string location = server.headers["location"]; if (!server.headers["location"].startswith("/") && !server.headers["location"].startswith("http")) { location = tools.getcurrentpath(url) + location; } rsb.insert(urlstart, location); return sendhttprequest(count, host, port, payload, rsb.tostring(), timeout, encoding, false); } } //根据请求头解析 if (server.headers.containskey(content_length)) { int length = int.parse(server.headers[content_length]); while (sum < length && sw.elapsedmilliseconds < timeout) { int readsize = length - sum; len = clientsocket.client.receive(responsebody, sum, readsize, socketflags.none); if (len > 0) { sum += len; } } } //解析chunked传输 else if (server.headers.containskey(transfer_encoding)) { //读取长度 int chunkedsize = 0; byte[] chunkedbyte = new byte[1]; //读取总长度 sum = 0; do { string ctmp = ""; do { len = clientsocket.client.receive(chunkedbyte, 1, socketflags.none); ctmp += encoding.utf8.getstring(chunkedbyte); } while ((ctmp.indexof(ct) == -1) && (sw.elapsedmilliseconds < timeout)); chunkedsize = tools.converttointby16(ctmp.replace(ct, "")); //chunked的结束0 是结束标志,单个chunked块 结束 if (ctmp.equals(ct)) { continue; } if (chunkedsize == 0) { //结束了 break; } int onechunklen = 0; while (onechunklen < chunkedsize && sw.elapsedmilliseconds < timeout) { len = clientsocket.client.receive(responsebody, sum, chunkedsize - onechunklen, socketflags.none); if (len > 0) { onechunklen += len; sum += len; } } //判断 } while (sw.elapsedmilliseconds < timeout); } //connection close方式或未知body长度 else { while (sw.elapsedmilliseconds < timeout) { if (clientsocket.client.poll(timeout, selectmode.selectread)) { if (clientsocket.available > 0) { len = clientsocket.client.receive(responsebody, sum, (1024 * 200) - sum, socketflags.none); if (len > 0) { sum += len; } } else { break; } } } } //判断是否gzip if (server.headers.containskey(content_encoding)) { server.body = ungzip(responsebody, sum, encod); } else { server.body = encod.getstring(responsebody, 0, sum); } } } } } catch (exception e) { exception ee = new exception("http发包错误!错误消息:" + e.message + e.targetsite.name + "----发包编号:" + index); throw ee; } finally { sw.stop(); server.length = sum; server.runtime = (int)sw.elapsedmilliseconds; if (clientsocket != null) { clientsocket.close(); } } return server; } private static bool validateservercertificate(object sender, x509certificate certificate, x509chain chain, sslpolicyerrors sslpolicyerrors) { return true; } private static serverinfo sendhttpsrequest(int count, string host, int port, string payload, string request, int timeout, string encoding, boolean foward_302) { string index = thread.currentthread.name + http.index; stopwatch sw = new stopwatch(); sw.start(); serverinfo server = new serverinfo(); int sum = 0; tcpclient clientsocket = null; ; try { if (port > 0 && port <= 65556) { timeoutsocket tos = new timeoutsocket(); clientsocket = tos.connect(host, port, timeout); if (sw.elapsedmilliseconds >= timeout) { return server; } clientsocket.sendtimeout = timeout - tos.usetime; sslstream ssl = null; if (clientsocket.connected) { ssl = new sslstream(clientsocket.getstream(), false, new remotecertificatevalidationcallback(validateservercertificate)); sslprotocols protocol = sslprotocols.ssl3 | sslprotocols.ssl2 | sslprotocols.tls; ssl.authenticateasclient(host, null, protocol, false); if (ssl.isauthenticated) { checkcontentlength(ref server, ref request); server.request = request; byte[] requestbyte = encoding.utf8.getbytes(request); ssl.write(requestbyte); ssl.flush(); } } server.request = request; byte[] responsebody = new byte[1024 * 1000]; int len = 0; //获取header头 string tmp = ""; stringbuilder sb = new stringbuilder(); stringbuilder bulider = new stringbuilder(); clientsocket.receivetimeout = timeout - (int)sw.elapsedmilliseconds; do { byte[] responseheader = new byte[1]; int read = ssl.readbyte(); char c = (char)read; sb.append(c); if (c.equals(t)) { tmp = string.concat(sb[sb.length - 4], sb[sb.length - 3], sb[sb.length - 2], c); } } while (!tmp.equals(ctrl) && sw.elapsedmilliseconds < timeout); server.header = sb.tostring().replace(ctrl, ""); string[] headers = regex.split(server.header, ct); //处理header doheader(ref server, ref headers); //自动修正编码 if (!string.isnullorempty(server.encoding)) { encoding = server.encoding; } encoding encod = encoding.getencoding(encoding); //302 301跳转 if ((server.code == 302 || server.code == 301) && foward_302) { int urlstart = server.request.indexof(" "); int urlend = server.request.indexof(" http"); if (urlstart != -1 && urlend != -1) { string url = server.request.substring(urlstart + 1, urlend - urlstart - 1); if (!server.headers["location"].startswith("/") && !server.headers["location"].startswith("https")) { server.request = server.request.replace(url, tools.getcurrentpath(url) + server.headers["location"]); } else { server.request = server.request.replace(url, server.headers["location"]); } return sendhttpsrequest(count, host, port, payload, server.request, timeout, encoding, false); } } //根据请求头解析 if (server.headers.containskey(content_length)) { int length = int.parse(server.headers[content_length]); while (sum < length && sw.elapsedmilliseconds < timeout) { len = ssl.read(responsebody, sum, length - sum); if (len > 0) { sum += len; } } } //解析chunked传输 else if (server.headers.containskey(transfer_encoding)) { //读取长度 int chunkedsize = 0; byte[] chunkedbyte = new byte[1]; //读取总长度 sum = 0; do { string ctmp = ""; do { len = ssl.read(chunkedbyte, 0, 1); ctmp += encoding.utf8.getstring(chunkedbyte); } while (ctmp.indexof(ct) == -1 && sw.elapsedmilliseconds < timeout); chunkedsize = tools.converttointby16(ctmp.replace(ct, "")); //chunked的结束0 是结束标志,单个chunked块 结束 if (ctmp.equals(ct)) { continue; } if (chunkedsize == 0) { //结束了 break; } int onechunklen = 0; while (onechunklen < chunkedsize && sw.elapsedmilliseconds < timeout) { len = ssl.read(responsebody, sum, chunkedsize - onechunklen); if (len > 0) { onechunklen += len; sum += len; } } //判断 } while (sw.elapsedmilliseconds < timeout); } //connection close方式或未知body长度 else { while (sw.elapsedmilliseconds < timeout) { if (clientsocket.client.poll(timeout, selectmode.selectread)) { if (clientsocket.available > 0) { len = ssl.read(responsebody, sum, (1024 * 200) - sum); if (len > 0) { sum += len; } } else { break; } } } } //判断是否gzip if (server.headers.containskey(content_encoding)) { server.body = ungzip(responsebody, sum, encod); } else { server.body = encod.getstring(responsebody, 0, sum); } } } catch (exception e) { exception ee = new exception("https发包错误!错误消息:" + e.message + "----发包编号:" + index); throw ee; } finally { sw.stop(); server.length = sum; server.runtime = (int)sw.elapsedmilliseconds; if (clientsocket != null) { clientsocket.close(); } } return server; } public static string ungzip(byte[] data, int len, encoding encoding) { string str = ""; memorystream ms = new memorystream(data, 0, len); gzipstream gs = new gzipstream(ms, compressionmode.decompress); memorystream outbuf = new memorystream(); byte[] block = new byte[1024]; try { while (true) { int bytesread = gs.read(block, 0, block.length); if (bytesread <= 0) { break; } else { outbuf.write(block, 0, bytesread); } } str = encoding.getstring(outbuf.toarray()); } catch (exception e) { tools.syslog("解压gzip发生异常----" + e.message); } finally { outbuf.close(); gs.close(); ms.close(); } return str; } public static string gethtmlencoding(string header, string body) { if (string.isnullorempty(header) && string.isnullorempty(body)) { return ""; } body = body.toupper(); match m = regex.match(header, @"charsets*=s*""?(?<charset>[^""]*)", regexoptions.ignorecase); if (m.success) { return m.groups["charset"].value.toupper(); } else { if (string.isnullorempty(body)) { return ""; } m = regex.match(body, @"charsets*=s*""?(?<charset>[^""]*)", regexoptions.ignorecase); if (m.success) { return m.groups["charset"].value.toupper(); } } return ""; } } }
以上就是关于c# socket发送http/https请求的核心代码了,需要的朋友可以参考一下。