807 lines
23 KiB
C#
807 lines
23 KiB
C#
#region License
|
|
/*
|
|
* HttpListenerRequest.cs
|
|
*
|
|
* This code is derived from System.Net.HttpListenerRequest.cs of Mono
|
|
* (http://www.mono-project.com).
|
|
*
|
|
* The MIT License
|
|
*
|
|
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
|
* Copyright (c) 2012-2014 sta.blockhead
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
#endregion
|
|
|
|
#region Authors
|
|
/*
|
|
* Authors:
|
|
* Gonzalo Paniagua Javier <gonzalo@novell.com>
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Specialized;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Text;
|
|
|
|
namespace WebSocketSharp.Net
|
|
{
|
|
/// <summary>
|
|
/// Provides access to a request to the <see cref="HttpListener"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The HttpListenerRequest class cannot be inherited.
|
|
/// </remarks>
|
|
public sealed class HttpListenerRequest
|
|
{
|
|
#region Private Static Fields
|
|
|
|
private static byte [] _100continue =
|
|
Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
|
|
|
|
#endregion
|
|
|
|
#region Private Fields
|
|
|
|
private string [] _acceptTypes;
|
|
private bool _chunked;
|
|
private Encoding _contentEncoding;
|
|
private long _contentLength;
|
|
private bool _contentLengthWasSet;
|
|
private HttpListenerContext _context;
|
|
private CookieCollection _cookies;
|
|
private WebHeaderCollection _headers;
|
|
private Guid _identifier;
|
|
private Stream _inputStream;
|
|
private bool _keepAlive;
|
|
private bool _keepAliveWasSet;
|
|
private string _method;
|
|
private NameValueCollection _queryString;
|
|
private string _rawUrl;
|
|
private Uri _referer;
|
|
private Uri _url;
|
|
private string [] _userLanguages;
|
|
private Version _version;
|
|
|
|
#endregion
|
|
|
|
#region Internal Constructors
|
|
|
|
internal HttpListenerRequest (HttpListenerContext context)
|
|
{
|
|
_context = context;
|
|
_contentLength = -1;
|
|
_headers = new WebHeaderCollection ();
|
|
_identifier = Guid.NewGuid ();
|
|
_version = HttpVersion.Version10;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Properties
|
|
|
|
/// <summary>
|
|
/// Gets the media types which are acceptable for the response.
|
|
/// </summary>
|
|
/// <value>
|
|
/// An array of <see cref="string"/> that contains the media type names in
|
|
/// the Accept request-header or <see langword="null"/> if the request didn't
|
|
/// include an Accept header.
|
|
/// </value>
|
|
public string [] AcceptTypes {
|
|
get {
|
|
return _acceptTypes;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets an error code that identifies a problem with the client's
|
|
/// certificate.
|
|
/// </summary>
|
|
/// <value>
|
|
/// Always returns <c>0</c>.
|
|
/// </value>
|
|
public int ClientCertificateError {
|
|
get {
|
|
// TODO: Always returns 0.
|
|
/*
|
|
if (no_get_certificate)
|
|
throw new InvalidOperationException (
|
|
"Call GetClientCertificate method before accessing this property.");
|
|
|
|
return client_cert_error;
|
|
*/
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the encoding used with the entity body data included in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="Encoding"/> that represents the encoding used with the entity
|
|
/// body data or <see cref="Encoding.Default"/> if the request didn't include
|
|
/// the information about the encoding.
|
|
/// </value>
|
|
public Encoding ContentEncoding {
|
|
get {
|
|
return _contentEncoding ?? (_contentEncoding = Encoding.Default);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the size of the entity body data included in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="long"/> that represents the value of the Content-Length
|
|
/// entity-header. The value is a number of bytes in the entity body data.
|
|
/// <c>-1</c> if the size isn't known.
|
|
/// </value>
|
|
public long ContentLength64 {
|
|
get {
|
|
return _contentLength;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the media type of the entity body included in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="string"/> that represents the value of the Content-Type
|
|
/// entity-header.
|
|
/// </value>
|
|
public string ContentType {
|
|
get {
|
|
return _headers ["Content-Type"];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the cookies included in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="CookieCollection"/> that contains the cookies included in
|
|
/// the request.
|
|
/// </value>
|
|
public CookieCollection Cookies {
|
|
get {
|
|
return _cookies ?? (_cookies = _headers.GetCookies (false));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the request has the entity body.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if the request has the entity body; otherwise, <c>false</c>.
|
|
/// </value>
|
|
public bool HasEntityBody {
|
|
get {
|
|
return _contentLength > 0 || _chunked;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the HTTP headers used in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="NameValueCollection"/> that contains the HTTP headers used
|
|
/// in the request.
|
|
/// </value>
|
|
public NameValueCollection Headers {
|
|
get {
|
|
return _headers;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the HTTP method used in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="string"/> that represents the HTTP method used in the request.
|
|
/// </value>
|
|
public string HttpMethod {
|
|
get {
|
|
return _method;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a <see cref="Stream"/> that contains the entity body data included
|
|
/// in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="Stream"/> that contains the entity body data included in the
|
|
/// request.
|
|
/// </value>
|
|
public Stream InputStream {
|
|
get {
|
|
return _inputStream ??
|
|
(_inputStream = HasEntityBody
|
|
? _context.Connection.GetRequestStream (
|
|
_chunked, _contentLength)
|
|
: Stream.Null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the client that sent the request is
|
|
/// authenticated.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
|
|
/// </value>
|
|
public bool IsAuthenticated {
|
|
get {
|
|
var user = _context.User;
|
|
return user != null && user.Identity.IsAuthenticated;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the request is sent from the local
|
|
/// computer.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if the request is sent from the local computer; otherwise,
|
|
/// <c>false</c>.
|
|
/// </value>
|
|
public bool IsLocal {
|
|
get {
|
|
return RemoteEndPoint.Address.IsLocal ();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the HTTP connection is secured using the
|
|
/// SSL protocol.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if the HTTP connection is secured; otherwise, <c>false</c>.
|
|
/// </value>
|
|
public bool IsSecureConnection {
|
|
get {
|
|
return _context.Connection.IsSecure;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the request is a WebSocket connection
|
|
/// request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if the request is a WebSocket connection request; otherwise,
|
|
/// <c>false</c>.
|
|
/// </value>
|
|
public bool IsWebSocketRequest {
|
|
get {
|
|
return _method == "GET" &&
|
|
_version >= HttpVersion.Version11 &&
|
|
_headers.Contains ("Upgrade", "websocket") &&
|
|
_headers.Contains ("Connection", "Upgrade");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the client requests a persistent
|
|
/// connection.
|
|
/// </summary>
|
|
/// <value>
|
|
/// <c>true</c> if the client requests a persistent connection; otherwise,
|
|
/// <c>false</c>.
|
|
/// </value>
|
|
public bool KeepAlive {
|
|
get {
|
|
if (!_keepAliveWasSet) {
|
|
_keepAlive = _headers.Contains ("Connection", "keep-alive") ||
|
|
_version == HttpVersion.Version11
|
|
? true
|
|
: _headers.Contains ("Keep-Alive")
|
|
? !_headers.Contains ("Keep-Alive", "closed")
|
|
: false;
|
|
|
|
_keepAliveWasSet = true;
|
|
}
|
|
|
|
return _keepAlive;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the server endpoint as an IP address and a port number.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="System.Net.IPEndPoint"/> that represents the server endpoint.
|
|
/// </value>
|
|
public System.Net.IPEndPoint LocalEndPoint {
|
|
get {
|
|
return _context.Connection.LocalEndPoint;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the HTTP version used in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="Version"/> that represents the HTTP version used in the
|
|
/// request.
|
|
/// </value>
|
|
public Version ProtocolVersion {
|
|
get {
|
|
return _version;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the collection of query string variables used in the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="NameValueCollection"/> that contains the collection of query
|
|
/// string variables used in the request.
|
|
/// </value>
|
|
public NameValueCollection QueryString {
|
|
get {
|
|
return _queryString;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the raw URL (without the scheme, host and port) requested by the
|
|
/// client.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="string"/> that represents the raw URL requested by the
|
|
/// client.
|
|
/// </value>
|
|
public string RawUrl {
|
|
get {
|
|
return _rawUrl;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the client endpoint as an IP address and a port number.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="System.Net.IPEndPoint"/> that represents the client endpoint.
|
|
/// </value>
|
|
public System.Net.IPEndPoint RemoteEndPoint {
|
|
get {
|
|
return _context.Connection.RemoteEndPoint;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the request identifier of a incoming HTTP request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="Guid"/> that represents the identifier of a request.
|
|
/// </value>
|
|
public Guid RequestTraceIdentifier {
|
|
get {
|
|
return _identifier;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the URL requested by the client.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="Uri"/> that represents the URL requested by the client.
|
|
/// </value>
|
|
public Uri Url {
|
|
get {
|
|
return _url;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the URL of the resource from which the requested URL was obtained.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="Uri"/> that represents the value of the Referer
|
|
/// request-header or <see langword="null"/> if the request didn't include
|
|
/// an Referer header.
|
|
/// </value>
|
|
public Uri UrlReferrer {
|
|
get {
|
|
return _referer;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the information about the user agent originating the request.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="string"/> that represents the value of the User-Agent
|
|
/// request-header.
|
|
/// </value>
|
|
public string UserAgent {
|
|
get {
|
|
return _headers ["User-Agent"];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the server endpoint as an IP address and a port number.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="string"/> that represents the server endpoint.
|
|
/// </value>
|
|
public string UserHostAddress {
|
|
get {
|
|
return LocalEndPoint.ToString ();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the internet host name and port number (if present) specified by the
|
|
/// client.
|
|
/// </summary>
|
|
/// <value>
|
|
/// A <see cref="string"/> that represents the value of the Host
|
|
/// request-header.
|
|
/// </value>
|
|
public string UserHostName {
|
|
get {
|
|
return _headers ["Host"];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the natural languages which are preferred for the response.
|
|
/// </summary>
|
|
/// <value>
|
|
/// An array of <see cref="string"/> that contains the natural language names
|
|
/// in the Accept-Language request-header or <see langword="null"/> if the
|
|
/// request didn't include an Accept-Language header.
|
|
/// </value>
|
|
public string [] UserLanguages {
|
|
get {
|
|
return _userLanguages;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private void createQueryString (string query)
|
|
{
|
|
if (query == null || query.Length == 0) {
|
|
_queryString = new NameValueCollection (1);
|
|
return;
|
|
}
|
|
|
|
_queryString = new NameValueCollection ();
|
|
if (query [0] == '?')
|
|
query = query.Substring (1);
|
|
|
|
var components = query.Split ('&');
|
|
foreach (var component in components) {
|
|
var i = component.IndexOf ('=');
|
|
if (i == -1) {
|
|
_queryString.Add (null, HttpUtility.UrlDecode (component));
|
|
}
|
|
else {
|
|
var name = HttpUtility.UrlDecode (component.Substring (0, i));
|
|
var val = HttpUtility.UrlDecode (component.Substring (i + 1));
|
|
_queryString.Add (name, val);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Internal Methods
|
|
|
|
internal void AddHeader (string header)
|
|
{
|
|
var colon = header.IndexOf (':');
|
|
if (colon == -1) {
|
|
_context.ErrorMessage = "Invalid header";
|
|
return;
|
|
}
|
|
|
|
var name = header.Substring (0, colon).Trim ();
|
|
var val = header.Substring (colon + 1).Trim ();
|
|
var lower = name.ToLower (CultureInfo.InvariantCulture);
|
|
_headers.SetInternal (name, val, false);
|
|
|
|
if (lower == "accept") {
|
|
_acceptTypes = val.SplitHeaderValue (',').ToArray ();
|
|
return;
|
|
}
|
|
|
|
if (lower == "accept-language") {
|
|
_userLanguages = val.Split (',');
|
|
return;
|
|
}
|
|
|
|
if (lower == "content-length") {
|
|
long length;
|
|
if (Int64.TryParse (val, out length) && length >= 0) {
|
|
_contentLength = length;
|
|
_contentLengthWasSet = true;
|
|
}
|
|
else {
|
|
_context.ErrorMessage = "Invalid Content-Length header";
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (lower == "content-type") {
|
|
var contents = val.Split (';');
|
|
foreach (var content in contents) {
|
|
var tmp = content.Trim ();
|
|
if (tmp.StartsWith ("charset")) {
|
|
var charset = tmp.GetValue ("=");
|
|
if (charset != null && charset.Length > 0) {
|
|
try {
|
|
_contentEncoding = Encoding.GetEncoding (charset);
|
|
}
|
|
catch {
|
|
_context.ErrorMessage = "Invalid Content-Type header";
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (lower == "referer")
|
|
_referer = val.ToUri ();
|
|
}
|
|
|
|
internal void FinishInitialization ()
|
|
{
|
|
var host = _headers ["Host"];
|
|
var noHost = host == null || host.Length == 0;
|
|
if (_version > HttpVersion.Version10 && noHost) {
|
|
_context.ErrorMessage = "Invalid Host header";
|
|
return;
|
|
}
|
|
|
|
if (noHost)
|
|
host = UserHostAddress;
|
|
|
|
string path;
|
|
var rawUri = _rawUrl.ToUri ();
|
|
if (rawUri != null && rawUri.IsAbsoluteUri) {
|
|
host = rawUri.Host;
|
|
path = rawUri.PathAndQuery;
|
|
}
|
|
else
|
|
path = HttpUtility.UrlDecode (_rawUrl);
|
|
|
|
var colon = host.IndexOf (':');
|
|
if (colon != -1)
|
|
host = host.Substring (0, colon);
|
|
|
|
var scheme = IsWebSocketRequest ? "ws" : "http";
|
|
var url = String.Format (
|
|
"{0}://{1}:{2}{3}",
|
|
IsSecureConnection ? scheme + "s" : scheme,
|
|
host,
|
|
LocalEndPoint.Port,
|
|
path);
|
|
|
|
if (!Uri.TryCreate (url, UriKind.Absolute, out _url)) {
|
|
_context.ErrorMessage = "Invalid request url: " + url;
|
|
return;
|
|
}
|
|
|
|
createQueryString (_url.Query);
|
|
|
|
var encoding = Headers ["Transfer-Encoding"];
|
|
if (_version >= HttpVersion.Version11 &&
|
|
encoding != null &&
|
|
encoding.Length > 0) {
|
|
_chunked = encoding.ToLower () == "chunked";
|
|
if (!_chunked) {
|
|
_context.ErrorMessage = String.Empty;
|
|
_context.ErrorStatus = 501;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!_chunked && !_contentLengthWasSet) {
|
|
var method = _method.ToLower ();
|
|
if (method == "post" || method == "put") {
|
|
_context.ErrorMessage = String.Empty;
|
|
_context.ErrorStatus = 411;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
var expect = Headers ["Expect"];
|
|
if (expect != null &&
|
|
expect.Length > 0 &&
|
|
expect.ToLower () == "100-continue") {
|
|
var output = _context.Connection.GetResponseStream ();
|
|
output.InternalWrite (_100continue, 0, _100continue.Length);
|
|
}
|
|
}
|
|
|
|
// Returns true is the stream could be reused.
|
|
internal bool FlushInput ()
|
|
{
|
|
if (!HasEntityBody)
|
|
return true;
|
|
|
|
var length = 2048;
|
|
if (_contentLength > 0)
|
|
length = (int) Math.Min (_contentLength, (long) length);
|
|
|
|
var buffer = new byte [length];
|
|
while (true) {
|
|
// TODO: Test if MS has a timeout when doing this.
|
|
try {
|
|
var ares = InputStream.BeginRead (buffer, 0, length, null, null);
|
|
if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne (100))
|
|
return false;
|
|
|
|
if (InputStream.EndRead (ares) <= 0)
|
|
return true;
|
|
}
|
|
catch {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void SetRequestLine (string requestLine)
|
|
{
|
|
var parts = requestLine.Split (new char [] { ' ' }, 3);
|
|
if (parts.Length != 3) {
|
|
_context.ErrorMessage = "Invalid request line (parts)";
|
|
return;
|
|
}
|
|
|
|
_method = parts [0];
|
|
if (!_method.IsToken ()) {
|
|
_context.ErrorMessage = "Invalid request line (method)";
|
|
return;
|
|
}
|
|
|
|
_rawUrl = parts [1];
|
|
|
|
if (parts [2].Length != 8 || !parts [2].StartsWith ("HTTP/")) {
|
|
_context.ErrorMessage = "Invalid request line (version)";
|
|
return;
|
|
}
|
|
|
|
try {
|
|
_version = new Version (parts [2].Substring (5));
|
|
if (_version.Major < 1)
|
|
throw new Exception ();
|
|
}
|
|
catch {
|
|
_context.ErrorMessage = "Invalid request line (version)";
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Begins getting the client's X.509 v.3 certificate asynchronously.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This asynchronous operation must be completed by calling the
|
|
/// <see cref="EndGetClientCertificate"/> method. Typically, that method is
|
|
/// invoked by the <paramref name="requestCallback"/> delegate.
|
|
/// </remarks>
|
|
/// <returns>
|
|
/// An <see cref="IAsyncResult"/> that contains the status of the
|
|
/// asynchronous operation.
|
|
/// </returns>
|
|
/// <param name="requestCallback">
|
|
/// An <see cref="AsyncCallback"/> delegate that references the method(s)
|
|
/// called when the asynchronous operation completes.
|
|
/// </param>
|
|
/// <param name="state">
|
|
/// An <see cref="object"/> that contains a user defined object to pass to
|
|
/// the <paramref name="requestCallback"/> delegate.
|
|
/// </param>
|
|
/// <exception cref="NotImplementedException">
|
|
/// This method is not implemented.
|
|
/// </exception>
|
|
public IAsyncResult BeginGetClientCertificate (
|
|
AsyncCallback requestCallback, Object state)
|
|
{
|
|
// TODO: Not Implemented.
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ends an asynchronous operation to get the client's X.509 v.3 certificate.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This method completes an asynchronous operation started by calling the
|
|
/// <see cref="BeginGetClientCertificate"/> method.
|
|
/// </remarks>
|
|
/// <returns>
|
|
/// A <see cref="X509Certificate2"/> that contains the client's X.509 v.3
|
|
/// certificate.
|
|
/// </returns>
|
|
/// <param name="asyncResult">
|
|
/// An <see cref="IAsyncResult"/> obtained by calling the
|
|
/// <see cref="BeginGetClientCertificate"/> method.
|
|
/// </param>
|
|
/// <exception cref="NotImplementedException">
|
|
/// This method is not implemented.
|
|
/// </exception>
|
|
public X509Certificate2 EndGetClientCertificate (IAsyncResult asyncResult)
|
|
{
|
|
// TODO: Not Implemented.
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the client's X.509 v.3 certificate.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A <see cref="X509Certificate2"/> that contains the client's X.509 v.3
|
|
/// certificate.
|
|
/// </returns>
|
|
/// <exception cref="NotImplementedException">
|
|
/// This method is not implemented.
|
|
/// </exception>
|
|
public X509Certificate2 GetClientCertificate ()
|
|
{
|
|
// TODO: Not Implemented.
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a <see cref="string"/> that represents the current
|
|
/// <see cref="HttpListenerRequest"/>.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// A <see cref="string"/> that represents the current
|
|
/// <see cref="HttpListenerRequest"/>.
|
|
/// </returns>
|
|
public override string ToString ()
|
|
{
|
|
var buffer = new StringBuilder (64);
|
|
buffer.AppendFormat ("{0} {1} HTTP/{2}\r\n", _method, _rawUrl, _version);
|
|
foreach (var key in _headers.AllKeys)
|
|
buffer.AppendFormat ("{0}: {1}\r\n", key, _headers [key]);
|
|
|
|
buffer.Append ("\r\n");
|
|
return buffer.ToString ();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|