import 'dart:math'; import 'dart:typed_data'; import 'package:network_proxy/network/http/body_reader.dart'; import '../../utils/compress.dart'; import '../channel.dart'; import '../util/logger.dart'; import 'http.dart'; import 'http_headers.dart'; class HttpConstants { /// Line feed character /n static const int lf = 10; /// Carriage return /r static const int cr = 13; /// Horizontal space static const int sp = 32; /// Colon ':' static const int colon = 58; } enum State { readInitial, readHeader, body, done, } /// http编解码 abstract class HttpCodec implements Codec { final HttpParse _httpParse = HttpParse(); State _state = State.readInitial; late T message; BodyReader? bodyReader; T createMessage(List reqLine); @override T? decode(Uint8List data) { _httpParse.index = 0; //请求行 if (_state == State.readInitial) { init(); try { var initialLine = _readInitialLine(data); message = createMessage(initialLine); _state = State.readHeader; } catch (e, cause) { logger.e("解析请求行失败 [${String.fromCharCodes(data)}]", e, cause); rethrow; } } //请求头 if (_state == State.readHeader) { _readHeader(data, message); } //请求体 if (_state == State.body) { var result = bodyReader!.readBody(data.sublist(_httpParse.index)); if (result.isDone) { _state = State.done; message.body = result.body; } } if (_state == State.done) { message.body = _convertBody(message.body); _state = State.readInitial; return message; } return null; } void init() { _httpParse.reset(); bodyReader = null; } void initialLine(BytesBuilder buffer, T message); @override List encode(T message) { BytesBuilder builder = BytesBuilder(); //请求行 initialLine(builder, message); List? body = message.body; if (message.headers.isGzip) { body = gzipEncode(body!); } //请求头 message.headers.remove(HttpHeaders.TRANSFER_ENCODING); if (body != null && body.isNotEmpty) { message.headers.contentLength = body.length; } message.headers.forEach((key, values) { for (var v in values) { builder ..add(key.codeUnits) ..addByte(HttpConstants.colon) ..addByte(HttpConstants.sp) ..add(v.codeUnits) ..addByte(HttpConstants.cr) ..addByte(HttpConstants.lf); } }); builder.addByte(HttpConstants.cr); builder.addByte(HttpConstants.lf); //请求体 builder.add(body ?? Uint8List(0)); return builder.toBytes(); } //读取起始行 List _readInitialLine(Uint8List data) { int maxSize = min(data.length, Codec.defaultMaxInitialLineLength); return _httpParse.parseInitialLine(data, maxSize); } //读取请求头 void _readHeader(Uint8List data, T message) { if (_httpParse.parseHeader(data, message.headers)) { message.contentLength = message.headers.contentLength; _state = State.body; bodyReader = BodyReader(message); } } //转换body List? _convertBody(List? bytes) { if (bytes == null) { return null; } if (message.headers.isGzip) { bytes = gzipDecode(bytes); } return bytes; } } /// http请求编解码 class HttpRequestCodec extends HttpCodec { @override HttpRequest createMessage(List reqLine) { HttpMethod httpMethod = HttpMethod.valueOf(reqLine[0]); return HttpRequest(httpMethod, reqLine[1], protocolVersion: reqLine[2]); } @override void initialLine(BytesBuilder buffer, HttpRequest message) { //请求行 buffer ..add(message.method.name.codeUnits) ..addByte(HttpConstants.sp) ..add(message.uri.codeUnits) ..addByte(HttpConstants.sp) ..add(message.protocolVersion.codeUnits) ..addByte(HttpConstants.cr) ..addByte(HttpConstants.lf); } } /// http响应编解码 class HttpResponseCodec extends HttpCodec { @override HttpResponse createMessage(List reqLine) { var httpStatus = HttpStatus(int.parse(reqLine[1]), reqLine[2]); return HttpResponse(reqLine[0], httpStatus); } @override void initialLine(BytesBuilder buffer, HttpResponse message) { //状态行 buffer.add(message.protocolVersion.codeUnits); buffer.addByte(HttpConstants.sp); buffer.add(message.status.code.toString().codeUnits); buffer.addByte(HttpConstants.sp); buffer.add(message.status.reasonPhrase.codeUnits); buffer.addByte(HttpConstants.cr); buffer.addByte(HttpConstants.lf); } } /// http解析器 class HttpParse { int index = 0; BytesBuilder inBytes = BytesBuilder(); /// 解析请求行 List parseInitialLine(Uint8List data, int size) { List initialLine = []; for (int i = index; i < size; i++) { if (_isLineEnd(data, i)) { //请求行结束 Uint8List requestLine = data.sublist(index, i - 1); initialLine = _splitLine(requestLine); index = i + 1; break; } } if (initialLine.length != 3) { throw Exception("parseLine error ${String.fromCharCodes(data)}"); } return initialLine; } /// 解析请求头 bool parseHeader(Uint8List data, HttpHeaders headers) { if (inBytes.length > Codec.defaultMaxInitialLineLength) { inBytes.clear(); throw Exception("header too long"); } while (true) { Uint8List line = Uint8List(0); for (int i = index; i < data.length; i++) { if (_isLineEnd(data, i)) { line = data.sublist(index, i - 1); index = i + 1; break; } if (i == data.length - 1) { inBytes.add(data.sublist(index, i + 1)); index = i + 1; return false; } } if (line.isEmpty) { break; } if (inBytes.isNotEmpty) { inBytes.add(line); line = inBytes.toBytes(); inBytes.clear(); } var header = _splitHeader(line); headers.add(header[0], header[1]); } return true; } Uint8List parseLine(Uint8List data) { for (int i = index; i < data.length; i++) { if (_isLineEnd(data, i)) { var line = data.sublist(index, i - 1); index = i + 1; return line; } } return Uint8List(0); } void reset() { index = 0; } //是否行结束 bool _isLineEnd(List data, int index) { return index >= 1 && data[index] == HttpConstants.lf && data[index - 1] == HttpConstants.cr; } //分割行 List _splitLine(Uint8List data) { List lines = []; int start = 0; for (int i = 0; i < data.length; i++) { if (data[i] == HttpConstants.sp) { lines.add(String.fromCharCodes(data.sublist(start, i))); start = i + 1; if (lines.length == 2) { break; } } } lines.add(String.fromCharCodes(data.sublist(start))); return lines; } //分割头 List _splitHeader(List data) { List headers = []; for (int i = 0; i < data.length; i++) { if (data[i] == HttpConstants.colon && data[i + 1] == HttpConstants.sp) { headers.add(String.fromCharCodes(data.sublist(0, i))); headers.add(String.fromCharCodes(data.sublist(i + 2))); break; } } return headers; } }