HttpListenerRequest.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. #region License
  2. /*
  3. * HttpListenerRequest.cs
  4. *
  5. * This code is derived from HttpListenerRequest.cs (System.Net) of Mono
  6. * (http://www.mono-project.com).
  7. *
  8. * The MIT License
  9. *
  10. * Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
  11. * Copyright (c) 2012-2022 sta.blockhead
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining a copy
  14. * of this software and associated documentation files (the "Software"), to deal
  15. * in the Software without restriction, including without limitation the rights
  16. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  17. * copies of the Software, and to permit persons to whom the Software is
  18. * furnished to do so, subject to the following conditions:
  19. *
  20. * The above copyright notice and this permission notice shall be included in
  21. * all copies or substantial portions of the Software.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  26. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  28. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  29. * THE SOFTWARE.
  30. */
  31. #endregion
  32. #region Authors
  33. /*
  34. * Authors:
  35. * - Gonzalo Paniagua Javier <gonzalo@novell.com>
  36. */
  37. #endregion
  38. using System;
  39. using System.Collections.Generic;
  40. using System.Collections.Specialized;
  41. using System.Globalization;
  42. using System.IO;
  43. using System.Security.Cryptography.X509Certificates;
  44. using System.Text;
  45. namespace WebSocketSharp.Net
  46. {
  47. /// <summary>
  48. /// Represents an incoming HTTP request to a <see cref="HttpListener"/>
  49. /// instance.
  50. /// </summary>
  51. /// <remarks>
  52. /// This class cannot be inherited.
  53. /// </remarks>
  54. public sealed class HttpListenerRequest
  55. {
  56. #region Private Fields
  57. private static readonly byte[] _100continue;
  58. private string[] _acceptTypes;
  59. private bool _chunked;
  60. private HttpConnection _connection;
  61. private Encoding _contentEncoding;
  62. private long _contentLength;
  63. private HttpListenerContext _context;
  64. private CookieCollection _cookies;
  65. private static readonly Encoding _defaultEncoding;
  66. private WebHeaderCollection _headers;
  67. private string _httpMethod;
  68. private Stream _inputStream;
  69. private Version _protocolVersion;
  70. private NameValueCollection _queryString;
  71. private string _rawUrl;
  72. private Guid _requestTraceIdentifier;
  73. private Uri _url;
  74. private Uri _urlReferrer;
  75. private bool _urlSet;
  76. private string _userHostName;
  77. private string[] _userLanguages;
  78. #endregion
  79. #region Static Constructor
  80. static HttpListenerRequest ()
  81. {
  82. _100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
  83. _defaultEncoding = Encoding.UTF8;
  84. }
  85. #endregion
  86. #region Internal Constructors
  87. internal HttpListenerRequest (HttpListenerContext context)
  88. {
  89. _context = context;
  90. _connection = context.Connection;
  91. _contentLength = -1;
  92. _headers = new WebHeaderCollection ();
  93. _requestTraceIdentifier = Guid.NewGuid ();
  94. }
  95. #endregion
  96. #region Public Properties
  97. /// <summary>
  98. /// Gets the media types that are acceptable for the client.
  99. /// </summary>
  100. /// <value>
  101. /// <para>
  102. /// An array of <see cref="string"/> or <see langword="null"/>.
  103. /// </para>
  104. /// <para>
  105. /// The array contains the names of the media types specified in
  106. /// the value of the Accept header.
  107. /// </para>
  108. /// <para>
  109. /// <see langword="null"/> if the header is not present.
  110. /// </para>
  111. /// </value>
  112. public string[] AcceptTypes {
  113. get {
  114. var val = _headers["Accept"];
  115. if (val == null)
  116. return null;
  117. if (_acceptTypes == null) {
  118. _acceptTypes = val
  119. .SplitHeaderValue (',')
  120. .TrimEach ()
  121. .ToList ()
  122. .ToArray ();
  123. }
  124. return _acceptTypes;
  125. }
  126. }
  127. /// <summary>
  128. /// Gets an error code that identifies a problem with the certificate
  129. /// provided by the client.
  130. /// </summary>
  131. /// <value>
  132. /// An <see cref="int"/> that represents an error code.
  133. /// </value>
  134. /// <exception cref="NotSupportedException">
  135. /// This property is not supported.
  136. /// </exception>
  137. public int ClientCertificateError {
  138. get {
  139. throw new NotSupportedException ();
  140. }
  141. }
  142. /// <summary>
  143. /// Gets the encoding for the entity body data included in the request.
  144. /// </summary>
  145. /// <value>
  146. /// <para>
  147. /// A <see cref="Encoding"/> converted from the charset value of the
  148. /// Content-Type header.
  149. /// </para>
  150. /// <para>
  151. /// <see cref="Encoding.UTF8"/> if the charset value is not available.
  152. /// </para>
  153. /// </value>
  154. public Encoding ContentEncoding {
  155. get {
  156. if (_contentEncoding == null)
  157. _contentEncoding = getContentEncoding ();
  158. return _contentEncoding;
  159. }
  160. }
  161. /// <summary>
  162. /// Gets the length in bytes of the entity body data included in the
  163. /// request.
  164. /// </summary>
  165. /// <value>
  166. /// <para>
  167. /// A <see cref="long"/> converted from the value of the Content-Length
  168. /// header.
  169. /// </para>
  170. /// <para>
  171. /// -1 if the header is not present.
  172. /// </para>
  173. /// </value>
  174. public long ContentLength64 {
  175. get {
  176. return _contentLength;
  177. }
  178. }
  179. /// <summary>
  180. /// Gets the media type of the entity body data included in the request.
  181. /// </summary>
  182. /// <value>
  183. /// <para>
  184. /// A <see cref="string"/> or <see langword="null"/>.
  185. /// </para>
  186. /// <para>
  187. /// The string represents the value of the Content-Type header.
  188. /// </para>
  189. /// <para>
  190. /// <see langword="null"/> if the header is not present.
  191. /// </para>
  192. /// </value>
  193. public string ContentType {
  194. get {
  195. return _headers["Content-Type"];
  196. }
  197. }
  198. /// <summary>
  199. /// Gets the cookies included in the request.
  200. /// </summary>
  201. /// <value>
  202. /// <para>
  203. /// A <see cref="CookieCollection"/> that contains the cookies.
  204. /// </para>
  205. /// <para>
  206. /// An empty collection if not included.
  207. /// </para>
  208. /// </value>
  209. public CookieCollection Cookies {
  210. get {
  211. if (_cookies == null)
  212. _cookies = _headers.GetCookies (false);
  213. return _cookies;
  214. }
  215. }
  216. /// <summary>
  217. /// Gets a value indicating whether the request has the entity body data.
  218. /// </summary>
  219. /// <value>
  220. /// <c>true</c> if the request has the entity body data; otherwise,
  221. /// <c>false</c>.
  222. /// </value>
  223. public bool HasEntityBody {
  224. get {
  225. return _contentLength > 0 || _chunked;
  226. }
  227. }
  228. /// <summary>
  229. /// Gets the headers included in the request.
  230. /// </summary>
  231. /// <value>
  232. /// A <see cref="NameValueCollection"/> that contains the headers.
  233. /// </value>
  234. public NameValueCollection Headers {
  235. get {
  236. return _headers;
  237. }
  238. }
  239. /// <summary>
  240. /// Gets the HTTP method specified by the client.
  241. /// </summary>
  242. /// <value>
  243. /// A <see cref="string"/> that represents the HTTP method specified in
  244. /// the request line.
  245. /// </value>
  246. public string HttpMethod {
  247. get {
  248. return _httpMethod;
  249. }
  250. }
  251. /// <summary>
  252. /// Gets a stream that contains the entity body data included in
  253. /// the request.
  254. /// </summary>
  255. /// <value>
  256. /// <para>
  257. /// A <see cref="Stream"/> that contains the entity body data.
  258. /// </para>
  259. /// <para>
  260. /// <see cref="Stream.Null"/> if the entity body data is not available.
  261. /// </para>
  262. /// </value>
  263. public Stream InputStream {
  264. get {
  265. if (_inputStream == null) {
  266. _inputStream = _contentLength > 0 || _chunked
  267. ? _connection
  268. .GetRequestStream (_contentLength, _chunked)
  269. : Stream.Null;
  270. }
  271. return _inputStream;
  272. }
  273. }
  274. /// <summary>
  275. /// Gets a value indicating whether the client is authenticated.
  276. /// </summary>
  277. /// <value>
  278. /// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
  279. /// </value>
  280. public bool IsAuthenticated {
  281. get {
  282. return _context.User != null;
  283. }
  284. }
  285. /// <summary>
  286. /// Gets a value indicating whether the request is sent from the
  287. /// local computer.
  288. /// </summary>
  289. /// <value>
  290. /// <c>true</c> if the request is sent from the same computer as
  291. /// the server; otherwise, <c>false</c>.
  292. /// </value>
  293. public bool IsLocal {
  294. get {
  295. return _connection.IsLocal;
  296. }
  297. }
  298. /// <summary>
  299. /// Gets a value indicating whether a secure connection is used to send
  300. /// the request.
  301. /// </summary>
  302. /// <value>
  303. /// <c>true</c> if the connection is secure; otherwise, <c>false</c>.
  304. /// </value>
  305. public bool IsSecureConnection {
  306. get {
  307. return _connection.IsSecure;
  308. }
  309. }
  310. /// <summary>
  311. /// Gets a value indicating whether the request is a WebSocket handshake
  312. /// request.
  313. /// </summary>
  314. /// <value>
  315. /// <c>true</c> if the request is a WebSocket handshake request; otherwise,
  316. /// <c>false</c>.
  317. /// </value>
  318. public bool IsWebSocketRequest {
  319. get {
  320. return _httpMethod == "GET" && _headers.Upgrades ("websocket");
  321. }
  322. }
  323. /// <summary>
  324. /// Gets a value indicating whether a persistent connection is requested.
  325. /// </summary>
  326. /// <value>
  327. /// <c>true</c> if the request specifies that the connection is kept open;
  328. /// otherwise, <c>false</c>.
  329. /// </value>
  330. public bool KeepAlive {
  331. get {
  332. return _headers.KeepsAlive (_protocolVersion);
  333. }
  334. }
  335. /// <summary>
  336. /// Gets the endpoint to which the request is sent.
  337. /// </summary>
  338. /// <value>
  339. /// A <see cref="System.Net.IPEndPoint"/> that represents the server
  340. /// IP address and port number.
  341. /// </value>
  342. public System.Net.IPEndPoint LocalEndPoint {
  343. get {
  344. return _connection.LocalEndPoint;
  345. }
  346. }
  347. /// <summary>
  348. /// Gets the HTTP version specified by the client.
  349. /// </summary>
  350. /// <value>
  351. /// A <see cref="Version"/> that represents the HTTP version specified in
  352. /// the request line.
  353. /// </value>
  354. public Version ProtocolVersion {
  355. get {
  356. return _protocolVersion;
  357. }
  358. }
  359. /// <summary>
  360. /// Gets the query string included in the request.
  361. /// </summary>
  362. /// <value>
  363. /// <para>
  364. /// A <see cref="NameValueCollection"/> that contains the query
  365. /// parameters.
  366. /// </para>
  367. /// <para>
  368. /// Each query parameter is decoded in UTF-8.
  369. /// </para>
  370. /// <para>
  371. /// An empty collection if not included.
  372. /// </para>
  373. /// </value>
  374. public NameValueCollection QueryString {
  375. get {
  376. if (_queryString == null) {
  377. var url = Url;
  378. var query = url != null ? url.Query : null;
  379. _queryString = QueryStringCollection.Parse (query, _defaultEncoding);
  380. }
  381. return _queryString;
  382. }
  383. }
  384. /// <summary>
  385. /// Gets the raw URL specified by the client.
  386. /// </summary>
  387. /// <value>
  388. /// A <see cref="string"/> that represents the request target specified in
  389. /// the request line.
  390. /// </value>
  391. public string RawUrl {
  392. get {
  393. return _rawUrl;
  394. }
  395. }
  396. /// <summary>
  397. /// Gets the endpoint from which the request is sent.
  398. /// </summary>
  399. /// <value>
  400. /// A <see cref="System.Net.IPEndPoint"/> that represents the client
  401. /// IP address and port number.
  402. /// </value>
  403. public System.Net.IPEndPoint RemoteEndPoint {
  404. get {
  405. return _connection.RemoteEndPoint;
  406. }
  407. }
  408. /// <summary>
  409. /// Gets the trace identifier of the request.
  410. /// </summary>
  411. /// <value>
  412. /// A <see cref="Guid"/> that represents the trace identifier.
  413. /// </value>
  414. public Guid RequestTraceIdentifier {
  415. get {
  416. return _requestTraceIdentifier;
  417. }
  418. }
  419. /// <summary>
  420. /// Gets the URL requested by the client.
  421. /// </summary>
  422. /// <value>
  423. /// <para>
  424. /// A <see cref="Uri"/> or <see langword="null"/>.
  425. /// </para>
  426. /// <para>
  427. /// The Uri represents the URL parsed from the request.
  428. /// </para>
  429. /// <para>
  430. /// <see langword="null"/> if the URL cannot be parsed.
  431. /// </para>
  432. /// </value>
  433. public Uri Url {
  434. get {
  435. if (!_urlSet) {
  436. _url = HttpUtility
  437. .CreateRequestUrl (
  438. _rawUrl,
  439. _userHostName,
  440. IsWebSocketRequest,
  441. IsSecureConnection
  442. );
  443. _urlSet = true;
  444. }
  445. return _url;
  446. }
  447. }
  448. /// <summary>
  449. /// Gets the URI of the resource from which the requested URL was obtained.
  450. /// </summary>
  451. /// <value>
  452. /// <para>
  453. /// A <see cref="Uri"/> or <see langword="null"/>.
  454. /// </para>
  455. /// <para>
  456. /// The Uri represents the value of the Referer header.
  457. /// </para>
  458. /// <para>
  459. /// <see langword="null"/> if the header value is not available.
  460. /// </para>
  461. /// </value>
  462. public Uri UrlReferrer {
  463. get {
  464. var val = _headers["Referer"];
  465. if (val == null)
  466. return null;
  467. if (_urlReferrer == null)
  468. _urlReferrer = val.ToUri ();
  469. return _urlReferrer;
  470. }
  471. }
  472. /// <summary>
  473. /// Gets the user agent from which the request is originated.
  474. /// </summary>
  475. /// <value>
  476. /// <para>
  477. /// A <see cref="string"/> or <see langword="null"/>.
  478. /// </para>
  479. /// <para>
  480. /// The string represents the value of the User-Agent header.
  481. /// </para>
  482. /// <para>
  483. /// <see langword="null"/> if the header is not present.
  484. /// </para>
  485. /// </value>
  486. public string UserAgent {
  487. get {
  488. return _headers["User-Agent"];
  489. }
  490. }
  491. /// <summary>
  492. /// Gets the IP address and port number to which the request is sent.
  493. /// </summary>
  494. /// <value>
  495. /// A <see cref="string"/> that represents the server IP address and
  496. /// port number.
  497. /// </value>
  498. public string UserHostAddress {
  499. get {
  500. return _connection.LocalEndPoint.ToString ();
  501. }
  502. }
  503. /// <summary>
  504. /// Gets the server host name requested by the client.
  505. /// </summary>
  506. /// <value>
  507. /// <para>
  508. /// A <see cref="string"/> that represents the value of the Host header.
  509. /// </para>
  510. /// <para>
  511. /// It includes the port number if provided.
  512. /// </para>
  513. /// </value>
  514. public string UserHostName {
  515. get {
  516. return _userHostName;
  517. }
  518. }
  519. /// <summary>
  520. /// Gets the natural languages that are acceptable for the client.
  521. /// </summary>
  522. /// <value>
  523. /// <para>
  524. /// An array of <see cref="string"/> or <see langword="null"/>.
  525. /// </para>
  526. /// <para>
  527. /// The array contains the names of the natural languages specified in
  528. /// the value of the Accept-Language header.
  529. /// </para>
  530. /// <para>
  531. /// <see langword="null"/> if the header is not present.
  532. /// </para>
  533. /// </value>
  534. public string[] UserLanguages {
  535. get {
  536. var val = _headers["Accept-Language"];
  537. if (val == null)
  538. return null;
  539. if (_userLanguages == null)
  540. _userLanguages = val.Split (',').TrimEach ().ToList ().ToArray ();
  541. return _userLanguages;
  542. }
  543. }
  544. #endregion
  545. #region Private Methods
  546. private Encoding getContentEncoding ()
  547. {
  548. var val = _headers["Content-Type"];
  549. if (val == null)
  550. return _defaultEncoding;
  551. Encoding ret;
  552. return HttpUtility.TryGetEncoding (val, out ret)
  553. ? ret
  554. : _defaultEncoding;
  555. }
  556. #endregion
  557. #region Internal Methods
  558. internal void AddHeader (string headerField)
  559. {
  560. var start = headerField[0];
  561. if (start == ' ' || start == '\t') {
  562. _context.ErrorMessage = "Invalid header field";
  563. return;
  564. }
  565. var colon = headerField.IndexOf (':');
  566. if (colon < 1) {
  567. _context.ErrorMessage = "Invalid header field";
  568. return;
  569. }
  570. var name = headerField.Substring (0, colon).Trim ();
  571. if (name.Length == 0 || !name.IsToken ()) {
  572. _context.ErrorMessage = "Invalid header name";
  573. return;
  574. }
  575. var val = colon < headerField.Length - 1
  576. ? headerField.Substring (colon + 1).Trim ()
  577. : String.Empty;
  578. _headers.InternalSet (name, val, false);
  579. var lower = name.ToLower (CultureInfo.InvariantCulture);
  580. if (lower == "host") {
  581. if (_userHostName != null) {
  582. _context.ErrorMessage = "Invalid Host header";
  583. return;
  584. }
  585. if (val.Length == 0) {
  586. _context.ErrorMessage = "Invalid Host header";
  587. return;
  588. }
  589. _userHostName = val;
  590. return;
  591. }
  592. if (lower == "content-length") {
  593. if (_contentLength > -1) {
  594. _context.ErrorMessage = "Invalid Content-Length header";
  595. return;
  596. }
  597. long len;
  598. if (!Int64.TryParse (val, out len)) {
  599. _context.ErrorMessage = "Invalid Content-Length header";
  600. return;
  601. }
  602. if (len < 0) {
  603. _context.ErrorMessage = "Invalid Content-Length header";
  604. return;
  605. }
  606. _contentLength = len;
  607. return;
  608. }
  609. }
  610. internal void FinishInitialization ()
  611. {
  612. if (_userHostName == null) {
  613. _context.ErrorMessage = "Host header required";
  614. return;
  615. }
  616. var transferEnc = _headers["Transfer-Encoding"];
  617. if (transferEnc != null) {
  618. var compType = StringComparison.OrdinalIgnoreCase;
  619. if (!transferEnc.Equals ("chunked", compType)) {
  620. _context.ErrorStatusCode = 501;
  621. _context.ErrorMessage = "Invalid Transfer-Encoding header";
  622. return;
  623. }
  624. _chunked = true;
  625. }
  626. if (_httpMethod == "POST" || _httpMethod == "PUT") {
  627. if (_contentLength == -1 && !_chunked) {
  628. _context.ErrorStatusCode = 411;
  629. _context.ErrorMessage = "Content-Length header required";
  630. return;
  631. }
  632. if (_contentLength == 0 && !_chunked) {
  633. _context.ErrorStatusCode = 411;
  634. _context.ErrorMessage = "Invalid Content-Length header";
  635. return;
  636. }
  637. }
  638. var expect = _headers["Expect"];
  639. if (expect != null) {
  640. var compType = StringComparison.OrdinalIgnoreCase;
  641. if (!expect.Equals ("100-continue", compType)) {
  642. _context.ErrorStatusCode = 417;
  643. _context.ErrorMessage = "Invalid Expect header";
  644. return;
  645. }
  646. var output = _connection.GetResponseStream ();
  647. output.InternalWrite (_100continue, 0, _100continue.Length);
  648. }
  649. }
  650. internal bool FlushInput ()
  651. {
  652. var input = InputStream;
  653. if (input == Stream.Null)
  654. return true;
  655. var len = 2048;
  656. if (_contentLength > 0 && _contentLength < len)
  657. len = (int) _contentLength;
  658. var buff = new byte[len];
  659. while (true) {
  660. try {
  661. var ares = input.BeginRead (buff, 0, len, null, null);
  662. if (!ares.IsCompleted) {
  663. var timeout = 100;
  664. if (!ares.AsyncWaitHandle.WaitOne (timeout))
  665. return false;
  666. }
  667. if (input.EndRead (ares) <= 0)
  668. return true;
  669. }
  670. catch {
  671. return false;
  672. }
  673. }
  674. }
  675. internal bool IsUpgradeRequest (string protocol)
  676. {
  677. return _headers.Upgrades (protocol);
  678. }
  679. internal void SetRequestLine (string requestLine)
  680. {
  681. var parts = requestLine.Split (new[] { ' ' }, 3);
  682. if (parts.Length < 3) {
  683. _context.ErrorMessage = "Invalid request line (parts)";
  684. return;
  685. }
  686. var method = parts[0];
  687. if (method.Length == 0) {
  688. _context.ErrorMessage = "Invalid request line (method)";
  689. return;
  690. }
  691. if (!method.IsHttpMethod ()) {
  692. _context.ErrorStatusCode = 501;
  693. _context.ErrorMessage = "Invalid request line (method)";
  694. return;
  695. }
  696. var target = parts[1];
  697. if (target.Length == 0) {
  698. _context.ErrorMessage = "Invalid request line (target)";
  699. return;
  700. }
  701. var rawVer = parts[2];
  702. if (rawVer.Length != 8) {
  703. _context.ErrorMessage = "Invalid request line (version)";
  704. return;
  705. }
  706. if (!rawVer.StartsWith ("HTTP/", StringComparison.Ordinal)) {
  707. _context.ErrorMessage = "Invalid request line (version)";
  708. return;
  709. }
  710. Version ver;
  711. if (!rawVer.Substring (5).TryCreateVersion (out ver)) {
  712. _context.ErrorMessage = "Invalid request line (version)";
  713. return;
  714. }
  715. if (ver != HttpVersion.Version11) {
  716. _context.ErrorStatusCode = 505;
  717. _context.ErrorMessage = "Invalid request line (version)";
  718. return;
  719. }
  720. _httpMethod = method;
  721. _rawUrl = target;
  722. _protocolVersion = ver;
  723. }
  724. #endregion
  725. #region Public Methods
  726. /// <summary>
  727. /// Begins getting the certificate provided by the client asynchronously.
  728. /// </summary>
  729. /// <returns>
  730. /// An <see cref="IAsyncResult"/> instance that indicates the status of
  731. /// the operation.
  732. /// </returns>
  733. /// <param name="requestCallback">
  734. /// An <see cref="AsyncCallback"/> delegate that invokes the method called
  735. /// when the operation is complete.
  736. /// </param>
  737. /// <param name="state">
  738. /// An <see cref="object"/> that specifies a user defined object to pass
  739. /// to the callback delegate.
  740. /// </param>
  741. /// <exception cref="NotSupportedException">
  742. /// This method is not supported.
  743. /// </exception>
  744. public IAsyncResult BeginGetClientCertificate (
  745. AsyncCallback requestCallback, object state
  746. )
  747. {
  748. throw new NotSupportedException ();
  749. }
  750. /// <summary>
  751. /// Ends an asynchronous operation to get the certificate provided by
  752. /// the client.
  753. /// </summary>
  754. /// <returns>
  755. /// A <see cref="X509Certificate2"/> that represents an X.509 certificate
  756. /// provided by the client.
  757. /// </returns>
  758. /// <param name="asyncResult">
  759. /// An <see cref="IAsyncResult"/> instance returned when the operation
  760. /// started.
  761. /// </param>
  762. /// <exception cref="NotSupportedException">
  763. /// This method is not supported.
  764. /// </exception>
  765. public X509Certificate2 EndGetClientCertificate (IAsyncResult asyncResult)
  766. {
  767. throw new NotSupportedException ();
  768. }
  769. /// <summary>
  770. /// Gets the certificate provided by the client.
  771. /// </summary>
  772. /// <returns>
  773. /// A <see cref="X509Certificate2"/> that represents an X.509 certificate
  774. /// provided by the client.
  775. /// </returns>
  776. /// <exception cref="NotSupportedException">
  777. /// This method is not supported.
  778. /// </exception>
  779. public X509Certificate2 GetClientCertificate ()
  780. {
  781. throw new NotSupportedException ();
  782. }
  783. /// <summary>
  784. /// Returns a string that represents the current instance.
  785. /// </summary>
  786. /// <returns>
  787. /// A <see cref="string"/> that contains the request line and headers
  788. /// included in the request.
  789. /// </returns>
  790. public override string ToString ()
  791. {
  792. var buff = new StringBuilder (64);
  793. var fmt = "{0} {1} HTTP/{2}\r\n";
  794. var headers = _headers.ToString ();
  795. buff
  796. .AppendFormat (fmt, _httpMethod, _rawUrl, _protocolVersion)
  797. .Append (headers);
  798. return buff.ToString ();
  799. }
  800. #endregion
  801. }
  802. }