/// <summary> /// 飞行状态的移动 /// </summary> private void FlyingState() { YawRotate(targetPos, maxRollAngle); // 偏航 float y = (targetPos - transform.position).normalized.y; // 获取y轴移动方向 currentMoveSpeed = Mathf.Lerp(currentMoveSpeed, maxMoveSpeed, Time.deltaTime); transform.Translate(new Vector3(transform.forward.x, y, transform.forward.z) * currentMoveSpeed * Time.deltaTime, Space.World); // x,z轴方向用直升机自身方向 PitchRotate(maxPitchAngle); // 俯仰 飞行状态必俯仰 // 抵达目标点后更改状态 if (Vector3.Distance(transform.position, targetPos) < 5) { currentMoveSpeed = 0; if (isLanding) { currentFlyState = HState.Down; } else { currentFlyState = HState.Hover; } } }
/// <summary> /// 设置攻击目标 /// </summary> /// <param name="_enemy"></param> /// <param name="isMissile">武器是否是导弹</param> public void SetEnemy(Transform _enemy, bool _isMissile = true) { if (launchs.Length <= 0) { return; } enemy = _enemy; isMissile = _isMissile; if (currentFlyState == HState.Hover || currentFlyState == HState.Flying) { isNeedAttack = true; currentFlyState = HState.Aim; } }
/// <summary> /// 开始攻击 /// </summary> private IEnumerator Attack() { if (launchs.Length > 0) { for (int i = 0; i < weaponNumber; i++) { InitFirePower(launchs[0]); yield return(new WaitForSeconds(0.2f)); } yield return(new WaitForSeconds(0.2f)); enemy = null; attackPos = default(Vector3); currentFlyState = HState.Hover; } }
/// <summary> /// 降落状态 /// </summary> private void DownState() { PitchRotate(0); // 俯仰修正 RollRotate(0); // 横滚修正 float height = transform.position.y - Terrain.activeTerrain.SampleHeight(transform.position); if (height < 0.1) { ratorSound.Stop(); currentFlyState = HState.Halt; return; } transform.Translate(Vector3.down * Time.deltaTime * Mathf.Lerp(Mathf.Min(height, maxLiftSpeed), maxLiftSpeed, Time.deltaTime));// 起飞速度以离地高度与飞行速度做插值 // 控制旋翼声音 ratorSound.volume = height / 10; }
/// <summary> /// 设置攻击目标点 /// </summary> /// <param name="_enemy"></param> /// <param name="isMissile">武器是否是导弹</param> public void SetEnemy(Vector3 _attackPos, bool _isMissile = true) { if (launchs.Length <= 0) { return; } attackPos = _attackPos; isMissile = _isMissile; switch (currentFlyState) { case HState.Flying: case HState.Hover: case HState.Aim: isNeedAttack = true; currentFlyState = HState.Aim; break; default: break; } }
/// <summary> /// 起飞状态 /// </summary> private void UpState() { float height = transform.position.y - Terrain.activeTerrain.SampleHeight(transform.position); if (height > MinFlyHeght) { currentFlyState = HState.Flying; return; } //YawRotate(targetPos, maxRollAngle); // 起飞速度以离地高度与飞行速度做插值 transform.Translate(Vector3.up * Time.deltaTime * Mathf.Lerp(height, maxLiftSpeed, Time.deltaTime)); if (!ratorSound.isPlaying) { ratorSound.Play(); } // 控制旋翼声音 ratorSound.volume = height / 10; }
/// <summary> /// 设置目标点 /// </summary> /// <param name="_pos"></param> /// <param name="_speed"></param> /// <param name="_isLanding"></param> public void SetTargetPos(Vector3 _pos, float _speed, bool _isLanding) { targetPos = _pos; maxMoveSpeed = _speed; isLanding = _isLanding; IsAim = false; switch (currentFlyState) { case HState.Down: case HState.Halt: currentFlyState = HState.Up; break; case HState.Hover: case HState.Aim: currentFlyState = HState.Flying; break; default: break; } }
/** Execute the parser with the currently available data contained in * the buffer. The buffers position() and limit() need to be set * correctly (obviously) and a will be updated approriately when the * method returns to reflect the consumed data. */ public void Execute(ParserSettings settings, ByteBuffer data) { int p = (int) data.Position; int p_err = p; // this is used for pretty printing errors. // In case the headers don't provide information about the content // length, `execute` needs to be called with an empty buffer to // indicate that all the data has been send be the client/server, // else there is no way of knowing the message is complete. int len = (int) (data.Length - data.Position); if (0 == len) { if (State.body_identity_eof == state) settings.RaiseOnMessageComplete(this); } // in case the _previous_ call to the parser only has data to get to // the middle of certain fields, we need to update marks to point at // the beginning of the current buffer. switch (state) { case State.header_field: header_field_mark = p; break; case State.header_value: header_value_mark = p; break; case State.req_fragment: fragment_mark = p; url_mark = p; break; case State.req_query_string: query_string_mark = p; url_mark = p; break; case State.req_path: path_mark = p; // JACKSON ADDED, I assume java can fall through? url_mark = p; break; case State.req_host: case State.req_schema: case State.req_schema_slash: case State.req_schema_slash_slash: case State.req_port: case State.req_query_string_start: case State.req_fragment_start: url_mark = p; break; } // this is where the work gets done, traverse the available data... while (data.Position != data.Length) { p = (int) data.Position; int pe = (int) data.Length; byte ch = data.ReadByte (); // the current character to process. int c = -1; // utility variably used for up- and downcasing etc. int to_read = 0; // used to keep track of how much of body, etc. is left to read if (parsing_header (state)) { ++nread; if (nread > HTTP_MAX_HEADER_SIZE) { settings.RaiseOnError (this, "possible buffer overflow", data, p_err); } } switch (state) { /* * this state is used after a 'Connection: close' message * the parser will error out if it reads another message */ case State.dead: settings.RaiseOnError (this, "Connection already closed", data, p_err); // JACKSON: Added this break break; case State.start_res_or_res: if (CR == ch || LF == ch){ break; } flags = 0; content_length = -1; settings.RaiseOnMessageBegin (this); if (H == ch) state = State.res_or_resp_H; else { type = ParserType.HTTP_REQUEST; method = start_req_method_assign (ch); if (HttpMethod.ERROR == method) settings.RaiseOnError (this, "invalid method", data, p_err); index = 1; state = State.req_method; } break; case State.res_or_resp_H: if (T == ch) { type = ParserType.HTTP_RESPONSE; state = State.res_HT; } else { if (E != ch) settings.RaiseOnError (this, "not E", data, p_err); type = ParserType.HTTP_REQUEST; method = HttpMethod.HTTP_HEAD; index = 2; state = State.req_method; } break; case State.start_res: flags = 0; content_length = -1; settings.RaiseOnMessageBegin (this); switch (ch) { case H: state = State.res_H; break; case CR: case LF: break; default: settings.RaiseOnError (this, "Not H or CR/LF", data, p_err); break; } break; case State.res_H: if (strict && T != ch) settings.RaiseOnError (this, "Not T", data, p_err); state = State.res_HT; break; case State.res_HT: if (strict && T != ch) settings.RaiseOnError (this, "Not T2", data, p_err); state = State.res_HTT; break; case State.res_HTT: if (strict && P != ch) settings.RaiseOnError (this, "Not P", data, p_err); state = State.res_HTTP; break; case State.res_HTTP: if (strict && SLASH != ch) settings.RaiseOnError (this, "Not '/'", data, p_err); state = State.res_first_http_major; break; case State.res_first_http_major: if (!isDigit (ch)) settings.RaiseOnError (this, "Not a digit", data, p_err); http_major = (int) ch - 0x30; state = State.res_http_major; break; /* major HTTP version or dot */ case State.res_http_major: if (DOT == ch) { state = State.res_http_minor; break; } if (!isDigit (ch)) settings.RaiseOnError(this, "Not a digit", data, p_err); http_major *= 10; http_major += (ch - 0x30); if (http_major > 999) settings.RaiseOnError(this, "invalid http major version: " + http_major, data, p_err); break; /* first digit of minor HTTP version */ case State.res_first_http_minor: if (!isDigit (ch)) settings.RaiseOnError (this, "Not a digit", data, p_err); http_minor = (int)ch - 0x30; state = State.res_http_minor; break; /* minor HTTP version or end of request line */ case State.res_http_minor: if (SPACE == ch) { state = State.res_first_status_code; break; } if (!isDigit (ch)) settings.RaiseOnError(this, "Not a digit", data, p_err); http_minor *= 10; http_minor += (ch - 0x30); if (http_minor > 999) settings.RaiseOnError(this, "invalid http minor version: " + http_minor, data, p_err); break; case State.res_first_status_code: if (!isDigit (ch)) { if (SPACE == ch) break; settings.RaiseOnError (this, "Not a digit (status code)", data, p_err); } status_code = (int)ch - 0x30; state = State.res_status_code; break; case State.res_status_code: if (!isDigit (ch)) { switch (ch) { case SPACE: state = State.res_status; break; case CR: state = State.res_line_almost_done; break; case LF: state = State.header_field_start; break; default: settings.RaiseOnError(this, "not a valid status code", data, p_err); break; } break; } status_code *= 10; status_code += (int)ch - 0x30; if (status_code > 999) settings.RaiseOnError(this, "ridiculous status code:"+status_code, data, p_err); break; case State.res_status: /* the human readable status. e.g. "NOT FOUND" * we are not humans so just ignore this * we are not men, we are devo. */ if (CR == ch) { state = State.res_line_almost_done; break; } if (LF == ch) { state = State.header_field_start; break; } break; case State.res_line_almost_done: if (strict && LF != ch) settings.RaiseOnError (this, "not LF", data, p_err); state = State.header_field_start; break; case State.start_req: if (CR==ch || LF == LF) break; flags = 0; content_length = -1; settings.RaiseOnMessageBegin (this); method = start_req_method_assign (ch); if (HttpMethod.ERROR == method) settings.RaiseOnError (this, "invalid method", data, p_err); index = 1; state = State.req_method; break; case State.req_method: if (0 == ch) settings.RaiseOnError( this, "NULL in method", data, p_err); byte [] arr = HttpMethodBytes.GetBytes (method); if (SPACE == ch && index == arr.Length) state = State.req_spaces_before_url; else if (arr[index] == ch) { // wuhu! } else if (HttpMethod.HTTP_CONNECT == method) { if (1 == index && H == ch) { method = HttpMethod.HTTP_CHECKOUT; } else if (2 == index && P == ch) { method = HttpMethod.HTTP_COPY; } } else if (HttpMethod.HTTP_MKCOL == method) { if (1 == index && O == ch) { method = HttpMethod.HTTP_MOVE; } else if (1 == index && E == ch) { method = HttpMethod.HTTP_MERGE; } else if (2 == index && A == ch) { method = HttpMethod.HTTP_MKACTIVITY; } } else if (1 == index && HttpMethod.HTTP_POST == method && R == ch) { method = HttpMethod.HTTP_PROPFIND; } else if (1 == index && HttpMethod.HTTP_POST == method && U == ch) { method = HttpMethod.HTTP_PUT; } else if (4 == index && HttpMethod.HTTP_PROPFIND == method && P == ch) { method = HttpMethod.HTTP_PROPPATCH; } else { settings.RaiseOnError (this, "Invalid HTTP method", data, p_err); } ++index; break; /*__________________URL__________________*/ case State.req_spaces_before_url: if (SPACE == ch) break; if (SLASH == ch) { url_mark = p; path_mark = p; state = State.req_path; break; } if (isAtoZ (ch)) { url_mark = p; state = State.req_schema; break; } settings.RaiseOnError (this, "Invalid something", data, p_err); break; case State.req_schema: if (isAtoZ (ch)) break; if (COLON == ch) { state = State.req_schema_slash; break; } else if (DOT == ch) { state = State.req_host; break; } settings.RaiseOnError (this, "invalid char in schema: "+ch, data, p_err); break; case State.req_schema_slash: if (strict && SLASH != ch) settings.RaiseOnError (this, "invalid char in schema, not /", data, p_err); state = State.req_schema_slash_slash; break; case State.req_schema_slash_slash: if (strict && SLASH != ch) settings.RaiseOnError(this, "invalid char in schema, not /", data, p_err); state = State.req_host; break; case State.req_host: if (isAtoZ (ch)) break; if (isDigit (ch) || DOT == ch || DASH == ch) break; switch (ch) { case COLON: state = State.req_port; break; case SLASH: path_mark = p; break; case SPACE: /* The request line looks like: * "GET http://foo.bar.com HTTP/1.1" * That is, there is no path. */ settings.RaiseOnUrl (this, data, url_mark, p-url_mark); url_mark = -1; state = State.req_http_start; break; default: settings.RaiseOnError(this, "host error in method line", data, p_err); break; } break; case State.req_port: if (isDigit (ch)) break; switch (ch) { case SLASH: path_mark = p; state = State.req_path; break; case SPACE: /* The request line looks like: * "GET http://foo.bar.com:1234 HTTP/1.1" * That is, there is no path. */ settings.RaiseOnUrl (this,data,url_mark,p-url_mark); url_mark = -1; state = State.req_http_start; break; default: settings.RaiseOnError (this, "invalid port", data, p_err); break; } break; case State.req_path: if (usual (ch)) break; switch (ch) { case SPACE: settings.RaiseOnUrl (this,data,url_mark, p-url_mark); url_mark = -1; settings.RaiseOnPath(this,data,path_mark, p-path_mark); path_mark = -1; state = State.req_http_start; break; case CR: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; settings.RaiseOnPath(this,data,path_mark, p-path_mark); path_mark = -1; http_minor = 9; state = State.res_line_almost_done; break; case LF: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; settings.RaiseOnPath(this,data,path_mark, p-path_mark); path_mark = -1; http_minor = 9; state = State.header_field_start; break; case QMARK: settings.RaiseOnPath(this,data,path_mark, p-path_mark); path_mark = -1; state = State.req_query_string_start; break; case HASH: settings.RaiseOnPath(this,data,path_mark, p-path_mark); path_mark = -1; state = State.req_fragment_start; break; default: settings.RaiseOnError(this, "unexpected char in path", data, p_err); break; } break; case State.req_query_string_start: if (usual(ch)) { query_string_mark = p; state = State.req_query_string; break; } switch (ch) { case QMARK: break; case SPACE: settings.RaiseOnUrl(this, data, url_mark, p-url_mark); url_mark = -1; state = State.req_http_start; break; case CR: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; http_minor = 9; state = State.res_line_almost_done; break; case LF: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; http_minor = 9; state = State.header_field_start; break; case HASH: state = State.req_fragment_start; break; default: settings.RaiseOnError(this, "unexpected char in path", data, p_err); break; } break; case State.req_query_string: if (usual(ch)) { break; } switch (ch) { case QMARK: break; // allow extra '?' in query string case SPACE: settings.RaiseOnUrl(this, data, url_mark, p-url_mark); url_mark = -1; settings.RaiseOnQueryString(this, data, query_string_mark, p-query_string_mark); query_string_mark = -1; state = State.req_http_start; break; case CR: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; settings.RaiseOnQueryString(this, data, query_string_mark, p-query_string_mark); query_string_mark = -1; http_minor = 9; state = State.res_line_almost_done; break; case LF: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; settings.RaiseOnQueryString(this, data, query_string_mark, p-query_string_mark); query_string_mark = -1; http_minor = 9; state = State.header_field_start; break; case HASH: settings.RaiseOnQueryString(this, data, query_string_mark, p-query_string_mark); query_string_mark = -1; state = State.req_fragment_start; break; default: settings.RaiseOnError(this, "unexpected char in path", data, p_err); break; } break; case State.req_fragment_start: if (usual(ch)) { fragment_mark = p; state = State.req_fragment; break; } switch (ch) { case SPACE: settings.RaiseOnUrl(this, data, url_mark, p-url_mark); url_mark = -1; state = State.req_http_start; break; case CR: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; http_minor = 9; state = State.res_line_almost_done; break; case LF: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; http_minor = 9; state = State.header_field_start; break; case QMARK: fragment_mark = p; state = State.req_fragment; break; case HASH: break; default: settings.RaiseOnError(this, "unexpected char in path", data, p_err); break; } break; case State.req_fragment: if (usual(ch)) { break; } switch (ch) { case SPACE: settings.RaiseOnUrl(this, data, url_mark, p-url_mark); url_mark = -1; settings.RaiseOnFragment(this, data, fragment_mark, p-fragment_mark); fragment_mark = -1; state = State.req_http_start; break; case CR: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; settings.RaiseOnFragment(this, data, query_string_mark, p-query_string_mark); fragment_mark = -1; http_minor = 9; state = State.res_line_almost_done; break; case LF: settings.RaiseOnUrl(this,data,url_mark, p-url_mark); url_mark = -1; settings.RaiseOnFragment(this, data, query_string_mark, p-query_string_mark); fragment_mark = -1; http_minor = 9; state = State.header_field_start; break; case QMARK: case HASH: break; default: settings.RaiseOnError(this, "unexpected char in path", data, p_err); break; } break; /******************* URL *******************/ /******************* HTTP 1.1 *******************/ case State.req_http_start: switch (ch) { case H: state = State.req_http_H; break; case SPACE: break; default: settings.RaiseOnError(this, "error in req_http_H", data, p_err); break; } break; case State.req_http_H: if (strict && T != ch) settings.RaiseOnError(this, "unexpected char", data, p_err); state = State.req_http_HT; break; case State.req_http_HT: if (strict && T != ch) settings.RaiseOnError(this, "unexpected char", data, p_err); state = State.req_http_HTT; break; case State.req_http_HTT: if (strict && P != ch) settings.RaiseOnError(this, "unexpected char", data, p_err); state = State.req_http_HTTP; break; case State.req_http_HTTP: if (strict && SLASH != ch) settings.RaiseOnError(this, "unexpected char", data, p_err); state = State.req_first_http_major; break; /* first digit of major HTTP version */ case State.req_first_http_major: if (!isDigit(ch)) settings.RaiseOnError(this, "non digit in http major", data, p_err); http_major = (int)ch - 0x30; state = State.req_http_major; break; /* major HTTP version or dot */ case State.req_http_major: if (DOT == ch) { state = State.req_first_http_minor; break; } if (!isDigit(ch)) settings.RaiseOnError(this, "non digit in http major", data, p_err); http_major *= 10; http_major += (int)ch - 0x30; if (http_major > 999) settings.RaiseOnError(this, "ridiculous http major", data, p_err); break; /* first digit of minor HTTP version */ case State.req_first_http_minor: if (!isDigit(ch)) settings.RaiseOnError(this, "non digit in http minor", data, p_err); http_minor = (int)ch - 0x30; state = State.req_http_minor; break; case State.req_http_minor: if (ch == CR) { state = State.req_line_almost_done; break; } if (ch == LF) { state = State.header_field_start; break; } /* XXX allow spaces after digit? */ if (!isDigit(ch)) settings.RaiseOnError(this, "non digit in http minor", data, p_err); http_minor *= 10; http_minor += (int)ch - 0x30; if (http_minor > 999) settings.RaiseOnError(this, "ridiculous http minor", data, p_err); break; /* end of request line */ case State.req_line_almost_done: { if (ch != LF) settings.RaiseOnError(this, "missing LF after request line", data, p_err); state = State.header_field_start; break; } /******************* HTTP 1.1 *******************/ /******************* Header *******************/ case State.header_field_start: { if (ch == CR) { state = State.headers_almost_done; break; } if (ch == LF) { /* they might be just sending \n instead of \r\n so this would be * the second \n to denote the end of headers*/ state = State.headers_almost_done; if (!headers_almost_done(ch, settings)) settings.RaiseOnError(this, "header not properly completed", data, p_err); break; } c = upper(ch); if (c == 0) { settings.RaiseOnError(this, "invalid char in header", data, p_err); }; header_field_mark = p; index = 0; state = State.header_field; switch (c) { case C: header_state = HState.C; break; case P: header_state = HState.matching_proxy_connection; break; case T: header_state = HState.matching_transfer_encoding; break; case U: header_state = HState.matching_upgrade; break; default: header_state = HState.general; break; } break; } case State.header_field: { c = UPCASE[ch]; if (0 != c) { switch (header_state) { case HState.general: break; case HState.C: index++; header_state = (O == c ? HState.CO : HState.general); break; case HState.CO: index++; header_state = (N == c ? HState.CON : HState.general); break; case HState.CON: index++; switch (c) { case N: header_state = HState.matching_connection; break; case T: header_state = HState.matching_content_length; break; default: header_state = HState.general; break; } break; /* connection */ case HState.matching_connection: index++; if (index > CONNECTION.Length || c != CONNECTION[index]) { header_state = HState.general; } else if (index == CONNECTION.Length-1) { header_state = HState.connection; } break; /* proxy-connection */ case HState.matching_proxy_connection: index++; if (index > PROXY_CONNECTION.Length || c != PROXY_CONNECTION[index]) { header_state = HState.general; } else if (index == PROXY_CONNECTION.Length-1) { header_state = HState.connection; } break; /* content-length */ case HState.matching_content_length: index++; if (index > CONTENT_LENGTH.Length || c != CONTENT_LENGTH[index]) { header_state = HState.general; } else if (index == CONTENT_LENGTH.Length-1) { header_state = HState.content_length; } break; /* transfer-encoding */ case HState.matching_transfer_encoding: index++; if (index > TRANSFER_ENCODING.Length || c != TRANSFER_ENCODING[index]) { header_state = HState.general; } else if (index == TRANSFER_ENCODING.Length-1) { header_state = HState.transfer_encoding; } break; /* upgrade */ case HState.matching_upgrade: index++; if (index > UPGRADE.Length || c != UPGRADE[index]) { header_state = HState.general; } else if (index == UPGRADE.Length-1) { header_state = HState.upgrade; } break; case HState.connection: case HState.content_length: case HState.transfer_encoding: case HState. upgrade: if (SPACE != ch) header_state = HState.general; break; default: settings.RaiseOnError(this, "Unknown Header State", data, p_err); break; } // switch: header_state break; } // 0 != c if (COLON == ch) { settings.RaiseOnHeaderField(this, data, header_field_mark, p-header_field_mark); header_field_mark = -1; state = State.header_value_start; break; } if (CR == ch) { state = State.header_almost_done; settings.RaiseOnHeaderField(this, data, header_field_mark, p-header_field_mark); header_field_mark = -1; break; } if (ch == LF) { settings.RaiseOnHeaderField(this, data, header_field_mark, p-header_field_mark); header_field_mark = -1; state = State.header_field_start; break; } settings.RaiseOnError(this, "invalid header field", data, p_err); break; } case State.header_value_start: { if (SPACE == ch) break; header_value_mark = p; state = State.header_value; index = 0; c = UPCASE[ch]; if (c == 0) { if (CR == ch) { settings.RaiseOnHeaderValue(this, data, header_value_mark, p-header_value_mark); header_value_mark = -1; header_state = HState.general; state = State.header_almost_done; break; } if (LF == ch) { settings.RaiseOnHeaderValue(this, data, header_value_mark, p-header_value_mark); header_value_mark = -1; state = State.header_field_start; break; } header_state = HState.general; break; } switch (header_state) { case HState.upgrade: flags |= F_UPGRADE; header_state = HState.general; break; case HState.transfer_encoding: /* looking for 'Transfer-Encoding: chunked' */ if (C == c) { header_state = HState.matching_transfer_encoding_chunked; } else { header_state = HState.general; } break; case HState.content_length: if (!isDigit(ch)) { settings.RaiseOnError(this, "Content-Length not numeric", data, p_err); } content_length = (int)ch - 0x30; break; case HState.connection: /* looking for 'Connection: keep-alive' */ if (K == c) { header_state = HState.matching_connection_keep_alive; /* looking for 'Connection: close' */ } else if (C == c) { header_state = HState.matching_connection_close; } else { header_state = HState.general; } break; default: header_state = HState.general; break; } break; } // header value start case State.header_value: { c = UPCASE[ch]; if (c == 0) { if (CR == ch) { settings.RaiseOnHeaderValue(this, data, header_value_mark, p-header_value_mark); header_value_mark = -1; state = State.header_almost_done; break; } if (LF == ch) { settings.RaiseOnHeaderValue(this, data, header_value_mark, p-header_value_mark); header_value_mark = -1; if (!header_almost_done(ch)) { settings.RaiseOnError(this,"incorrect header ending, expection LF", data, p_err); } break; } break; } switch (header_state) { case HState.general: break; case HState.connection: case HState.transfer_encoding: settings.RaiseOnError(this, "Shouldn't be here", data, p_err); break; case HState.content_length: if (ch == ' ') break; if (!isDigit(ch)) settings.RaiseOnError(this, "Content-Length not numeric", data, p_err); content_length *= 10; content_length += (int)ch - 0x30; break; /* Transfer-Encoding: chunked */ case HState.matching_transfer_encoding_chunked: index++; if (index > CHUNKED.Length || c != CHUNKED[index]) { header_state = HState.general; } else if (index == CHUNKED.Length-1) { header_state = HState.transfer_encoding_chunked; } break; /* looking for 'Connection: keep-alive' */ case HState.matching_connection_keep_alive: index++; if (index > KEEP_ALIVE.Length || c != KEEP_ALIVE[index]) { header_state = HState.general; } else if (index == KEEP_ALIVE.Length-1) { header_state = HState.connection_keep_alive; } break; /* looking for 'Connection: close' */ case HState.matching_connection_close: index++; if (index > CLOSE.Length || c != CLOSE[index]) { header_state = HState.general; } else if (index == CLOSE.Length-1) { header_state = HState.connection_close; } break; case HState.transfer_encoding_chunked: case HState.connection_keep_alive: case HState.connection_close: if (SPACE != ch) header_state = HState.general; break; default: state = State.header_value; header_state = HState.general; break; } break; } // header_value case State.header_almost_done: if (!header_almost_done(ch)) settings.RaiseOnError(this,"incorrect header ending, expection LF", data, p_err); break; case State.headers_almost_done: if (!headers_almost_done(ch, settings)) settings.RaiseOnError(this, "header not properly completed", data, p_err); break; /******************* Header *******************/ /******************* Body *******************/ case State.body_identity: to_read = min(pe - p, content_length); //TODO change to use buffer? if (to_read > 0) { settings.RaiseOnBody(this, data, p, to_read); data.Position = p+to_read; content_length -= to_read; if (content_length == 0) { settings.RaiseOnMessageComplete(this); state = new_message(); } } break; case State.body_identity_eof: to_read = pe - p; // TODO change to use buffer ? if (to_read > 0) { settings.RaiseOnBody(this, data, p, to_read); data.Position = p+to_read; } break; /******************* Body *******************/ /******************* Chunk *******************/ case State.chunk_size_start: if (0 == (flags & F_CHUNKED)) settings.RaiseOnError(this, "not chunked", data, p_err); c = UNHEX[ch]; if (c == -1) { Console.WriteLine ("THE CHAR: '{0}'", (char) ch); settings.RaiseOnError(this, "invalid hex char in chunk content length", data, p_err); } content_length = c; state = State.chunk_size; break; case State.chunk_size: if (0 == (flags & F_CHUNKED)) settings.RaiseOnError(this, "not chunked", data, p_err); if (CR == ch) { state = State.chunk_size_almost_done; break; } c = UNHEX[ch]; if (c == -1) { if (SEMI == ch || SPACE == ch) { state = State.chunk_parameters; break; } Console.WriteLine ("THE CHAR: '{0}'", (char) ch); settings.RaiseOnError(this, "invalid hex char in chunk content length", data, p_err); } content_length *= 16; content_length += c; break; case State.chunk_parameters: if (0 == (flags & F_CHUNKED)) settings.RaiseOnError(this, "not chunked", data, p_err); /* just ignore this shit. TODO check for overflow */ if (CR == ch) { state = State.chunk_size_almost_done; break; } break; case State.chunk_size_almost_done: if (0 == (flags & F_CHUNKED)) { settings.RaiseOnError(this, "not chunked", data, p_err); } if (strict && LF != ch) { settings.RaiseOnError(this, "expected LF at end of chunk size", data, p_err); } if (0 == content_length) { flags |= F_TRAILING; state = State.header_field_start; } else { state = State.chunk_data; } break; case State.chunk_data: { if (0 == (flags & F_CHUNKED)) { settings.RaiseOnError(this, "not chunked", data, p_err); } to_read = min(pe-p, content_length); if (to_read > 0) { settings.RaiseOnBody(this, data, p, to_read); data.Position = p+to_read; } if (to_read == content_length) { state = State.chunk_data_almost_done; } content_length -= to_read; break; } case State.chunk_data_almost_done: if (0 == (flags & F_CHUNKED)) { settings.RaiseOnError(this, "not chunked", data, p_err); } if (strict && CR != ch) { settings.RaiseOnError(this, "chunk data terminated incorrectly, expected CR", data, p_err); } state = State.chunk_data_done; break; case State.chunk_data_done: if (0 == (flags & F_CHUNKED)) { settings.RaiseOnError(this, "not chunked", data, p_err); } if (strict && LF != ch) { settings.RaiseOnError(this, "chunk data terminated incorrectly, expected LF", data, p_err); } state = State.chunk_size_start; break; /******************* Chunk *******************/ default: settings.RaiseOnError(this, "unhandled state", data, p_err); break; } // switch } // while p = (int) data.Position; /* Reaching this point assumes that we only received part of a * message, inform the callbacks about the progress made so far*/ settings.RaiseOnHeaderField (this, data, header_field_mark, p-header_field_mark); settings.RaiseOnHeaderValue (this, data, header_value_mark, p-header_value_mark); settings.RaiseOnFragment (this, data, fragment_mark, p-fragment_mark); settings.RaiseOnQueryString (this, data, query_string_mark, p-query_string_mark); settings.RaiseOnPath (this, data, path_mark, p-path_mark); settings.RaiseOnUrl (this, data, url_mark, p-url_mark); }