diff --git a/HttpBins/HttpServer.dll b/HttpBins/HttpServer.dll new file mode 100644 index 00000000..bf543068 Binary files /dev/null and b/HttpBins/HttpServer.dll differ diff --git a/HttpBins/HttpServer.pdb b/HttpBins/HttpServer.pdb new file mode 100644 index 00000000..f1cfd83f Binary files /dev/null and b/HttpBins/HttpServer.pdb differ diff --git a/HttpBins/HttpServer.xml b/HttpBins/HttpServer.xml new file mode 100644 index 00000000..fff737b5 --- /dev/null +++ b/HttpBins/HttpServer.xml @@ -0,0 +1,6183 @@ + + + + HttpServer + + + + + Used to read from a string object. + + + + + Base interface to read string tokens from different sources. + + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + + + + Assign a new buffer + + Buffer to process + + + + Consume current character. + + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + true if found; otherwise false. + + + + Read a character. + + Character if not EOF; otherwise null. + + + + Get a text line. + + + Will merge multiline headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + A string (can be ). + + Will not consume the delimiter. + + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + A string (can be ). + + Will not consume the delimiter. + + + + + Will read until specified delimiter is found. + + Character to stop at. + A string if the delimiter was found; otherwise null. + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + + + + Read until one of the delimiters are found. + + characters to stop at + A string if one of the delimiters was found; otherwise null. + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + + + + Read until a horizontal white space occurs. + + A string if a white space was found; otherwise null. + + + + Gets current character + + if end of buffer. + + + + Gets if end of buffer have been reached + + + + + Gets if more bytes can be processed. + + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + Gets or sets line number. + + + + + Gets next character + + if end of buffer. + + + + Gets number of bytes left. + + + + + Initializes a new instance of the class. + + Buffer to process. + + + + Initializes a new instance of the class. + + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + MUST be of type . + buffer needs to be of type string + + + + Assign a new buffer + + Buffer to process + MUST be of type . + buffer needs to be of type string + + + + Consume current character. + + + + + Get a text line. + + + Will merge multiline headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + A string (can be ). + InvalidOperationException. + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + A string (can be ). + InvalidOperationException. + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Read a character. + + + Character if not EOF; otherwise null. + + + + + Will read until specified delimiter is found. + + Character to stop at. + + A string if the delimiter was found; otherwise null. + + + Will trim away spaces and tabs from the end. + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until one of the delimiters are found. + + characters to stop at + + A string if one of the delimiters was found; otherwise null. + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until a horizontal white space occurs (or end, or end of line). + + + A string if a white space was found; otherwise null. + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + + true if found; otherwise false. + + + + + Gets or sets line number. + + + + + Gets if end of buffer have been reached + + + + + + Gets if more bytes can be processed. + + + + + + Gets next character + + if end of buffer. + + + + Gets current character + + if end of buffer. + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + + Gets number of bytes left. + + + + + Reads strings from a byte array. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Encoding to use when converting byte array to strings. + + + + Initializes a new instance of the class. + + Buffer to read from. + Encoding to use when converting byte array to strings. + + + + Assign a new buffer + + Buffer to process. + Where to start process buffer + Buffer length + Buffer needs to be a byte array + + + + Assign a new buffer + + Buffer to process + Buffer needs to be a byte array + + + + Consume current character. + + + + + Get a text line. + + + Will merge multi line headers. + + + + Read quoted string + + string if current character (in buffer) is a quote; otherwise null. + + + + Read until end of string, or to one of the delimiters are found. + + characters to stop at + + A string (can be ). + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until end of string, or to one of the delimiters are found. + + A string (can be ). + + Will not consume the delimiter. + + + + + Read to end of buffer, or until specified delimiter is found. + + Delimiter to find. + + A string (can be ). + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Consume specified characters + + One or more characters. + + + + Consumes horizontal white spaces (space and tab). + + + + + Consume horizontal white spaces and the specified character. + + Extra character to consume + + + + Read a character. + + + Character if not EOF; otherwise null. + + + + + Will read until specified delimiter is found. + + Character to stop at. + + A string if the delimiter was found; otherwise null. + + + Will trim away spaces and tabs from the end. + InvalidOperationException. + + + + Read until one of the delimiters are found. + + characters to stop at + + A string if one of the delimiters was found; otherwise null. + + + Will not consume the delimiter. + + InvalidOperationException. + + + + Read until a horizontal white space occurs. + + A string if a white space was found; otherwise null. + + + + Checks if one of the remaining bytes are a specified character. + + Character to find. + + true if found; otherwise false. + + + + + Gets or sets line number. + + + + + Gets if end of buffer have been reached + + + + + + Gets if more bytes can be processed. + + + + + + Gets next character + + if end of buffer. + + + + Gets current character + + if end of buffer. + + + + Gets or sets current position in buffer. + + + THINK before you manually change the position since it can blow up + the whole parsing in your face. + + + + + Gets total length of buffer. + + + + + + Gets number of bytes left. + + + + + Event arguments used when a new header have been parsed. + + + + + Initializes a new instance of the class. + + Name of header. + Header value. + Name cannot be empty + value is null. + + + + Initializes a new instance of the class. + + + + + Gets or sets header name. + + + + + Gets or sets header value. + + + + + Resource information. + + + Used by content providers to be able to get information + on resources (views, files etc). + + + + + Gets or sets date when resource was modified. + + + if not used. + + + Should always be universal time. + + + + + Gets or sets resource stream. + + + + + Loads resources from a specific location (such as assembly, hard drive etc). + + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Find all views in a folder/path. + + Absolute Uri path to files that should be found, can end with wild card. + Collection to add all view names to. + + + + Gets a resource. + + Uri path to resource. + Resource + Uri contains forbidden characters. + + + Resource resource = resources.Get("/files/user/user.png"); + + + + + + Parses Cookie header. + + + + + Used to parse header values + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Used by to filter out unwanted connections. + + + + + Initializes a new instance of the class. + + The socket. + + + + Gets or sets if socket can be accepted. + + + + + Gets socket. + + + + + Http listener + + + + + Start listener. + + Number of pending accepts. + + Make sure that you are subscribing on first. + + Listener have already been started. + Failed to start socket. + Invalid port number. + + + + Stop listener. + + + + + Gets listener address. + + + + + Gets if listener is secure. + + + + + Gets if listener have been started. + + + + + Gets or sets logger. + + + + + Gets listening port. + + + + + Gets the maximum content size. + + The content length limit. + + Used when responding to 100-continue. + + + + + A new request have been received. + + + + + Can be used to reject certain clients. + + + + + A HTTP exception have been thrown. + + + Fill the body with a user friendly error page, or redirect to somewhere else. + + + + + Collection of files. + + + + + Checks if a file exists. + + Name of the file (form item name) + + + + + Add a new file. + + File to add. + + + + Remove all files from disk. + + + + + Get a file + + Name in form + File if found; otherwise null. + + + + Gets number of files + + + + + Custom network stream to mark sockets as reusable when disposing the stream. + + + + + Creates a new instance of the class for the specified . + + + The that the will use to send and receive data. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Initializes a new instance of the class for the specified with the specified ownership. + + + The that the will use to send and receive data. + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + the value of the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specify the type of access given to the over the provided . + + + The parameter is null. + + + The parameter is not connected. + -or- + the property of the parameter is not . + -or- + the parameter is in a nonblocking state. + + + + + Creates a new instance of the class for the specified with the specified access rights and the specified ownership. + + + The that the will use to send and receive data. + + + A bitwise combination of the values that specifies the type of access given to the over the provided . + + + Set to true to indicate that the will take ownership of the ; otherwise, false. + + + The parameter is null. + + + The parameter is not connected. + -or- + The property of the parameter is not . + -or- + The parameter is in a nonblocking state. + + + + + Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + + + + + Releases the unmanaged resources used by the and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Request sent to a HTTP server. + + + + + + Base interface for request and response. + + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Gets body stream. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets headers. + + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Gets or sets connection header. + + + + + Gets cookies. + + + + + Gets all uploaded files. + + + + + Gets form parameters. + + + + + Gets or sets HTTP version. + + + + + Gets if request is an Ajax request. + + + + + Gets or sets HTTP method. + + + + + Gets query string and form parameters + + + + + Gets query string. + + + + + Gets requested URI. + + + + + Serves files in the web server. + + + + FileModule fileModule = new FileModule(); + fileModule.Resources.Add(new FileResources("/", "C:\\inetpub\\myweb")); + + + + + + HTTP Module + + + + + Process a request. + + Request information + What to do next. + + + + Initializes a new instance of the class. + + baseUri or basePath is null. + + + + Mime types that this class can handle per default + + + Contains the following mime types: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Will send a file to client. + + HTTP context containing outbound stream. + Response containing headers. + File stream + + + + Process a request. + + Request information + What to do next. + Failed to find file extension + Forbidden file type. + + + + Gets a list with all allowed content types. + + All other mime types will result in . + + + + Gets provider used to add files to the file manager, + + + + + An exception that can't be handled by the library have been thrown. + + + + + Initializes a new instance of the class. + + The exception. + + + + Gets caught exception. + + + + + Helper for content types. + + + + + Decodes forms that have multiple sections. + + + http://www.faqs.org/rfcs/rfc1867.html + + + + + Decodes body stream. + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + form-data + + + + + multipart/form-data + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + stream is null. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + A HTTP parser using delegates to which parsing methods. + + + + + Initializes a new instance of the class. + + + + + Parser method to copy all body bytes. + + + Needed since a TCP packet can contain multiple messages + after each other, or partial messages. + + + + Try to find a header name. + + + + + + Get header values. + + + Will also look for multi header values and automatically merge them to one line. + Content length is not a number. + + + + Toggle body bytes event. + + + + + + + + Raise the event, since we have successfully parsed a message and it's body. + + + + + First message line. + + Will always contain three elements. + Used to raise the or event + depending on the words in the array. + BadRequestException. + + + + Continue parsing a message + + Byte buffer containing bytes + Where to start the parsing + Number of bytes to parse + index where the parsing stopped. + Parsing failed. + + + + Parses the first line in a request/response. + + true if first line is well formatted; otherwise false. + Invalid request/response line. + + + + Reset parser to initial state. + + + + + Gets or sets current line number. + + + + + The request line has been parsed. + + + + + Response line has been parsed. + + + + + Parsed a header. + + + + + Received body bytes. + + + + + A message have been successfully parsed. + + + + + Used to be able to quickly swap parser method. + + + + + + Default log filter implementation. + + + + + Determines which classes can log + + + + + Checks if the specified type can send + log entries at the specified level. + + Log level + Type that want to write a log entry. + true if logging is allowed; otherwise false. + + + + Add a name space filter. + + Name space to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType(typeof(SipParser), LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + + + + Used to specify standard filter rules + + + Parser can only display errors. Transports only warnings. + + + + + Add filter for a type + + Type to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType(typeof(SipParser), LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + + + + Add filter for a type + + Type to add filter for. + Minimum log level required. + + + // Parsing can only add error and fatal messages + AddNamespace("SipSharp.Messages.Headers.Parsers", LogLevel.Error); + AddType("SipSharp.Messages.MessageFactory", LogLevel.Error); + + // Transport layer can only log warnings, errors and fatal messages + AddNamespace("SipSharp.Transports.*", LogLevel.Warning); + + + Type could not be identified. + + + + Checks if the specified type can send + log entries at the specified level. + + Log level + Type that want to write a log entry. + true if logging is allowed; otherwise false. + + + No filters = everything logged. = no logs. Don't use a rule with '*' or '.*' + + + + User have specified a wild card filter. + + + Wild card filters are used to log a name space and + all it's children name spaces. + + + + + Factory implementation used to create logs. + + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Response to a request. + + + + + Redirect user. + + Where to redirect to. + + Any modifications after a redirect will be ignored. + + + + + Gets connection type. + + + + + Gets cookies. + + + + + Gets HTTP version. + + + Default is HTTP/1.1 + + + + + Information about why a specific status code was used. + + + + + Status code that is sent to the client. + + Default is + + + + Gets or sets content type + + + + + Rules are used to perform operations before a request is being handled. + Rules can be used to create routing etc. + + + + + Process the incoming request. + + Request context information. + Processing result. + If any parameter is null. + + + + Used to access resources. + + + + + Add a new resource loader. + + Provider to add. + Manager have been started. + + + + Check if a resource exists. + + Uri to check + true if found; otherwise false. + + + if (manager.Exists("/views/user/view.haml")) + return true + + + + + + Get a resource. + + Uri path to resource. + Resource if found; otherwise null. + + + Resource resource = manager.Get("/views/user/view.haml"); + + + + + + Start manager. + + + + + Gets number of resource providers + + + + + Parses "Date" header. + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Content-type + + + + + Header in a message + + + Important! Each header should override ToString() + and return it's data correctly formatted as a HTTP header value. + + + + + Gets header name + + + + + Gets value as it would be sent back to client. + + + + + Header name. + + + + + Initializes a new instance of the class. + + Type of the content. + Value parameters. + + + + Initializes a new instance of the class. + + Type of the content. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets all parameters. + + + + + Gets content type. + + + + + Gets header name + + + + + Used to get or set properties on objects. + + + This class should be a bit faster than the standard reflection. + + + + + Get cached type. + + Type to get/set properties in + Type to use + + + + Flyweight design pattern implementation. + + Type of object. + + + + Initializes a new instance of the class. + + How large buffers to allocate. + + + + Get an object. + + Created object. + Will create one if queue is empty. + + + + Enqueues the specified buffer. + + Object to enqueue. + Buffer is is less than the minimum requirement. + + + + Used to create new objects. + + Type of objects to create. + Newly created object. + . + + + + Used to load/store sessions in the server. + + + + + Initializes a new instance of the class. + + Web server that the provider is for.. + Store to use. + + + + Initializes a new instance of the class. + + The server. + + Uses a file store. + + + + + Loads a session for all requests that got the session cookie. + + The sender. + The instance containing the event data. + + + + Gets current session + + Session if set, otherwise null. + + + + Gets or sets the session life time in minutes. + + The session life time. + + + + A session have been loaded. Use to access it. + + + + + Used to build headers. + + + + + Add a parser + + Header that the parser is for. + Parser implementation + + Will replace any existing parser for the specified header. + + + + + Add all default (built-in) parsers. + + + Will not replace previously added parsers. + + + + + Create a header parser + + implementation. + + + Uses attribute to find which headers + the parser is for. + + Will not replace previously added parsers. + + + + + Parse a header. + + Name of header + Header value + Header. + Value is not a well formatted header value. + + + + Arguments used when more body bytes have come. + + + + + Initializes a new instance of the class. + + buffer that contains the received bytes. + offset in buffer where to start processing. + number of bytes from that should be parsed. + buffer is null. + + + + Initializes a new instance of the class. + + + + + Gets or sets buffer that contains the received bytes. + + + + + Gets or sets number of bytes from that should be parsed. + + + + + Gets or sets offset in buffer where to start processing. + + + + + redirects from one URL to another. + + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Initializes a new instance of the class. + + Absolute path (no server name) + Absolute path (no server name) + true if request should be redirected, false if the request URI should be replaced. + + server.Add(new RedirectRule("/", "/user/index")); + + + + + Process the incoming request. + + Request context. + Processing result. + If any parameter is null. + + + + Gets string to match request URI with. + + Is compared to request.Uri.AbsolutePath + + + + Gets whether the server should redirect the client instead of simply modifying the URI. + + + false means that the rule will replace + the current request URI with the new one from this class. + true means that a redirect response is sent to the client. + + + + + Gets where to redirect. + + + + + cookie sent by the client/browser + + + + + + Constructor. + + cookie identifier + cookie content + id or content is null + id is empty + + + + Gets the cookie HTML representation. + + cookie string + + + + Gets the cookie identifier. + + + + + Gets value. + + + Set to null to remove cookie. + + + + + A request have been parsed successfully by the server. + + + + + Initializes a new instance of the class. + + Received request. + + + + Gets received request. + + + + + Context that received a HTTP request. + + + + + Disconnect context. + + + + + Gets if current context is using a secure connection. + + + + + Gets logger. + + + + + Gets remote end point + + + + + Gets stream used to send/receive data to/from remote end point. + + + + The stream can be any type of stream, do not assume that it's a network + stream. For instance, it can be a or a ZipStream. + + + + + + Gets the currently handled request + + The request. + + + + Gets the response that is going to be sent back + + The response. + + + + File sent from remote end. + + + + + Gets or sets content type. + + + + + Gets or sets name in form. + + + + + Gets or sets name original file name + + + + + Gets or sets filename for locally stored file. + + + + + Client X.509 certificate, X.509 chain, and any SSL policy errors encountered + during the SSL stream creation + + + + + Initializes a new instance of the class. + + The certificate. + Client security certificate chain. + Any SSL policy errors encountered during the SSL stream creation. + + + + Client security certificate + + + + + Client security certificate chain + + + + + Any SSL policy errors encountered during the SSL stream creation + + + + + Provides sessions. + + Type of session object + + Will always use files for sessions (utilizing the binary formatter), but can + also cache them in memory. + + If caching is enabled, it will only write sessions to disk every 20 seconds if they have + been accessed the last minute (to not keep writing dead sessions to disk). + + + + + + Initializes a new instance of the class. + + Session type must use [Serializable] attribute. + + + + Create a new session. + + + + + + Load session + + Id of session. + Session if found; otherwise null. + sessionId is null. + + + + Load session when a new request comes in. + + + + + + + Save a session to disk. + + Session to write to disk. + + You are responsible for writing sessions to disk if you are not using caching. + + + + + Start the session system and hook + + + + + + Stop session handling + + + + + Gets or sets session cookie name + + + + + Gets or sets cache + + + + + Gets current session. + + + + + Gets or sets number of seconds before a session expired. + + + A session have expired if nothing have accessed it for X seconds. This + class modifies the write time each time it's accessed. + + + + + Determines if cookie should be set in the response. + + + + + Invoked when a session have been changed and should be written to disc. + + + + + Base class for sessions. + + + Your class must be tagged with attribute to be able to use sessions. + + + + + The session have been changed and should be written to disk. + + + + + Session have been changed. + + + + + Gets or sets when session was accessed last + + + + + Gets current session. + + + + + Gets or sets session id. + + + + + Gets or sets when the session was last written to disk. + + + + + Used when the request line have been successfully parsed. + + + + + Initializes a new instance of the class. + + The HTTP method. + The URI path. + The HTTP version. + + + + Initializes a new instance of the class. + + + + + Gets or sets HTTP method. + + + Should be one of the methods declared in . + + + + + Gets or sets requested URI path. + + + + + Gets or sets the version of the SIP protocol that the client want to use. + + + + + cookie being sent back to the browser. + + + + + + Constructor. + + cookie identifier + cookie content + cookie expiration date. Use for session cookie. + id or content is null + id is empty + + + + Create a new cookie + + name identifying the cookie + cookie value + when the cookie expires. Setting will delete the cookie when the session is closed. + Path to where the cookie is valid + Domain that the cookie is valid for. + + + + Create a new cookie + + Name and value will be used + when the cookie expires. + + + + Gets the cookie HTML representation. + + cookie string + + + + Gets when the cookie expires. + + means that the cookie expires when the session do so. + + + + Gets path that the cookie is valid under. + + + + + Used to define which headers a parse is for. + + + + + Initializes a new instance of the class. + + Name of the header. + + + + Gets name of header that this parser is for. + + + + + Collection of headers. + + + + + Gets a header + + header name. + header if found; otherwise null. + + + + Something failed during parsing. + + + + + Request couldn't be parsed successfully. + + + + + Exception thrown from HTTP server. + + + + + Initializes a new instance of the class. + + HTTP status code. + Exception description. + + + + Initializes a new instance of the class. + + HTTP status code. + Exception description. + Inner exception. + + + + Gets HTTP status code. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + Provides resources. + + + + + Get all view names from a folder. + + Path to find views in. + A collection of view names (without path). + + + + Add a new resource loader. + + Provider to add. + Manager have been started. + + + + Start manager. + + + + + Check if a resource exists. + + Uri to check + true if found; otherwise false. + + + if (manager.Exists("/views/user/view.haml")) + return true + + + + + + Get a resource. + + Uri path to resource. + Resource if found; otherwise null. + + + Resource resource = manager.Get("/views/user/view.haml"); + + + + + + Gets number of resource providers + + + + + Collection of parameters. + + + or is not used since each parameter can + have multiple values. + + + + + Collection of parameters + + + + + Get a parameter. + + + + + + + Add a query string parameter. + + Parameter name + Value + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Initializes a new instance of the class. + + Collections to merge. + + Later collections will overwrite parameters from earlier collections. + + + + + Initializes a new instance of the class. + + + + + Get a list of string arrays. + + + + + + Get parameters + + Sub array (text array) + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Get a parameter. + + + + + + + Add a query string parameter. + + Parameter name + Value + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Result of processing. + + + + + Continue with the next handler + + + + + No more handlers can process the request. + + + The server will process the response object and + generate a HTTP response from it. + + + + + Response have been sent back by the handler. + + + This option should only be used if you are streaming + something or sending back a custom result. The server will + not process the response object or send anything back + to the client. + + + + + A HTTP context + + + + + + + + Initializes a new instance of the class. + + Socket received from HTTP listener. + Context used to parse incoming messages. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Disconnect context. + + + + + Close and release socket. + + + + + Create stream used to send and receive bytes from the socket. + + Socket to wrap + Stream + Stream could not be created. + + + + Interpret incoming data. + + + + + + A request was received from the parser. + + + + + + + Parse all complete requests in buffer. + + + offset in buffer where parsing stopped. + Parsing failed. + + + + Start content. + + A socket operation failed. + Reading from stream failed. + + + + Gets currently executing HTTP context. + + + + + Gets or sets description + + + + + gets factory used to build request objects + + + + + Gets socket + + + + + Gets remove end point + + + + + Gets network stream. + + + + + Gets the currently handled request + + The request. + + + + Gets the response that is going to be sent back + + The response. + + + + Gets logger. + + + + + Gets if current context is using a secure connection. + + + + + Triggered for all requests in the server (after the response have been sent) + + + + + Triggered for current request (after the response have been sent) + + + + + A new request have been received. + + + + + A new request have been received (invoked for ALL requests) + + + + + Client have been disconnected. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Used to store all headers that that aren't recognized. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Gets or sets value + + + + + Gets header name + + + + + The Connection general-header field allows the sender to specify options + that are desired for that particular connection and MUST NOT be + communicated by proxies over further connections. + + + + HTTP/1.1 proxies MUST parse the Connection header field before a + message is forwarded and, for each connection-token in this field, + remove any header field(s) from the message with the same name as the + connection-token. Connection options are signaled by the presence of + a connection-token in the Connection header field, not by any + corresponding additional header field(s), since the additional header + field may not be sent if there are no parameters associated with that + connection option. + + Message headers listed in the Connection header MUST NOT include + end-to-end headers, such as Cache-Control. + + HTTP/1.1 defines the "close" connection option for the sender to + signal that the connection will be closed after completion of the + response. For example, + + Connection: close + + in either the request or the response header fields indicates that + the connection SHOULD NOT be considered `persistent' (section 8.1) + after the current request/response is complete. + + HTTP/1.1 applications that do not support persistent connections MUST + include the "close" connection option in every message. + + A system receiving an HTTP/1.0 (or lower-version) message that + includes a Connection header MUST, for each connection-token in this + field, remove and ignore any header field(s) from the message with + the same name as the connection-token. This protects against mistaken + forwarding of such header fields by pre-HTTP/1.1 proxies. See section + 19.6.2 in RFC2616. + + + + + + Header name + + + + + Default connection header for HTTP/1.0 + + + + + Default connection header for HTTP/1.1 + + + + + Initializes a new instance of the class. + + Connection type. + The parameters. + + + + Initializes a new instance of the class. + + The type. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets connection parameters. + + + + + Gets or sets connection type + + + + + Gets header name + + + + + Type of HTTP connection + + + + + Connection is closed after each request-response + + + + + Connection is kept alive for X seconds (unless another request have been made) + + + + + Parameter in + + + + + Gets *last* value. + + + Parameters can have multiple values. This property will always get the last value in the list. + + String if any value exist; otherwise null. + + + + Gets or sets name. + + + + + Gets a list of all values. + + + + + A parameter in . + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets last value. + + + Parameters can have multiple values. This property will always get the last value in the list. + + String if any value exist; otherwise null. + + + + Gets or sets name. + + + + + Gets a list of all values. + + + + + Secure version of the HTTP listener. + + + + + Http listener. + + + + + Initializes a new instance of the class. + + The address. + The port. + + + + Initializes a new instance of the class. + + The address. + The port. + The HTTP factory. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Factory used to create different types in the framework. + Created HTTP listener. + + + + Creates a new instance with default factories. + + Address that the listener should accept connections on. + Port that listener should accept connections on. + Certificate to use + Created HTTP listener. + + + + Create a new context + + Accepted socket + A new context. + + + Throwing exception if in debug mode and not exception handler have been specified. + + + + Start listener. + + Number of pending accepts. + + Make sure that you are subscribing on first. + + Listener have already been started. + Failed to start socket. + Invalid port number. + + + + Stop listener. + + + + + Gets HTTP factory used to create types used by this HTTP library. + + + + + Gets or sets the maximum number of bytes that the request body can contain. + + The content length limit. + + + Used when responding to 100-continue. + + + 0 = turned off. + + + + + + Gets listener address. + + + + + Gets if listener is secure. + + + + + Gets if listener have been started. + + + + + Gets or sets logger. + + + + + Gets listening port. + + + + + A new request have been received. + + + + + Can be used to reject certain clients. + + + + + A HTTP exception have been thrown. + + + Fill the body with a user friendly error page, or redirect to somewhere else. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Initializes a new instance of the class. + + Address to accept new connections on. + Port to accept connections on. + Certificate securing the connection. + + + + Create a new context + + Accepted socket + A new context. + + Factory is assigned by the on each incoming request. + + + + + Gets if listener is secure. + + + + + + Gets or sets SSL protocol. + + + + + Gets or sets if client certificate should be used. + + + + + A response have been received. + + + + + Initializes a new instance of the class. + + The response. + + + + Gets or sets response. + + + + + Implements HTTP Digest authentication. It's more secure than Basic auth since password is + encrypted with a "key" from the server. + + + Keep in mind that the password is encrypted with MD5. Use a combination of SSL and digest auth to be secure. + + + + + Authenticates requests + + + + + Authenticate request + + Authorization header send by web client + Realm to authenticate in, typically a domain name. + HTTP Verb used in the request. + User if authentication was successful; otherwise null. + + + + Create a authentication challenge. + + Realm that the user should authenticate in + A WWW-Authenticate header. + If realm is empty or null. + + + + Gets authenticator scheme + + + digest + + + + + Initializes a new instance of the class. + + Supplies users during authentication process. + + + + Used by test classes to be able to use hardcoded values + + + + + An authentication response have been received from the web browser. + Check if it's correct + + Contents from the Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + + Authentication object that is stored for the request. A user class or something like that. + + if authenticationHeader is invalid + If any of the parameters is empty or null. + + + + Encrypts parameters into a Digest string + + Realm that the user want to log into. + User logging in + Users password. + HTTP method. + Uri/domain that generated the login prompt. + Quality of Protection. + "Number used ONCE" + Hexadecimal request counter. + "Client Number used ONCE" + Digest encrypted string + + + + + + Md5 hex encoded "userName:realm:password", without the quotes. + Md5 hex encoded "method:uri", without the quotes + Quality of Protection + "Number used ONCE" + Hexadecimal request counter. + Client number used once + + + + + Create a authentication challenge. + + Realm that the user should authenticate in + A correct auth request. + If realm is empty or null. + + + + Gets the current nonce. + + + + + + Gets the Md5 hash bin hex2. + + To be hashed. + + + + + determines if the nonce is valid or has expired. + + nonce value (check wikipedia for info) + true if the nonce has not expired. + + + + Gets authentication scheme name + + + + + Gets authenticator scheme + + + + digest + + + + + Session in the system + + + + + Gets or sets session id. + + + + + Factory creating null logger. + + + + + Initializes a new instance of the class. + + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Logger instance. + + + + + HTTP methods. + + + + + Unknown method + + + + + Posting data + + + + + Get data + + + + + Update data + + + + + Remove data + + + + + Get only HTTP headers. + + + + + Options HTTP 1.1 header. + + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Request couldn't be parsed successfully. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Exception description. + + + + Arguments for . + + + + + Initializes a new instance of the class. + + The context. + + + + Gets or sets thrown exception + + + + + Gets or sets if error page was provided. + + + + + Gets requested resource. + + + + + Gets response to send + + + + + Convention over configuration server. + + + Used to make it easy to create and use a web server. + + All resources must exist in the "YourProject.Content" namespace (or a subdirectory called "Content" relative to yourapp.exe). + + + + + + Http server. + + + + + Initializes a new instance of the class. + + Factory used to create objects used in this library. + + + + Initializes a new instance of the class. + + + + + Add a decoder. + + decoder to add + + Adding zero decoders will make the server add the + default ones which is and . + + + + + Add a new router. + + Router to add + Server have been started. + + + + Add a file module + + Module to add + module is null. + Cannot add modules when server have been started. + + + + Add a HTTP listener. + + + Listener have been started. + + + + An error have occurred and we need to send a result pack to the client + + The context. + The exception. + + Invoke base class () to send the contents + of . + + + + + Called before anything else. + + The context. + + Looks after a in the request and will + use the if found. + + + + + All server modules are about to be invoked. + + The context. + + Called when routers have been invoked but no modules yet. + + + + + A request have arrived but not yet been processed yet. + + The context. + + Default implementation adds a Date header and Server header. + + + + + Go through all modules and check if any of them can handle the current request. + + + + + + + Process result (check if it should be sent back or not) + + + + true if request was processed properly.; otherwise false. + + + + Processes all routers. + + Request context. + Processing result. + + + + Requests authentication from the user. + + Host/domain name that the server hosts. + + Used when calculating hashes in Digest authentication. + + + + + + + Send a response. + + + + + + + + Start http server. + + Number of pending connections. + + + + Stops the server + + true if all modules should be removed. + + + + Gets the authentication provider. + + + A authentication provider is used to keep track of all authentication types + that can be used. + + + + + Gets or sets number of bytes that a body can be. + + + + Used to determine the answer to a 100-continue request. + + + 0 = turned off. + + + + + + Gets current server. + + + Only valid when a request have been received and is being processed. + + + + + Gets or sets the maximum size of request body (in bytes) + + + + + Gets or sets server name. + + + Used in the "Server" header when serving requests. + + + + + Invoked just before a response is sent back to the client. + + + + + Invoked *after* the web server has tried to handled the request. + + + The event can be used to handle the request after all routes and modules + have tried to process the request. + + + + + Invoked *before* the web server has tried to handled the request. + + + Event can be used to load a session from a cookie or to force + authentication or anything other you might need t do before a request + is handled. + + + + + An error page have been requested. + + + + + Initializes a new instance of the class. + + + + + Class to make dynamic binding of redirects. Instead of having to specify a number of similar redirect rules + a regular expression can be used to identify redirect URLs and their targets. + + + [a-z0-9]+)", "/users/${target}/?find=true", RegexOptions.IgnoreCase) + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + + [a-zA-Z0-9]+)", "/user/${first}")); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to use, can be null + + [a-zA-Z0-9]+)", "/user/{first}", RegexOptions.IgnoreCase)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + + + + Initializes a new instance of the class. + + Expression to match URL + Expression to generate URL + Regular expression options to apply + true if request should be redirected, false if the request URI should be replaced. + + [a-zA-Z0-9]+)", "/user/${first}", RegexOptions.None)); + Result of ie. /employee1 will then be /user/employee1 + ]]> + + Argument is null. + + + + + Process the incoming request. + + Request context. + Processing result. + If any parameter is null. + + + + Load resources from disk. + + + + + Default forbidden characters. + + + + + relative to absolute path mappings. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Request URI path + Disk path + + File names should not be included in URI or path. + + + + new FileResources("/files/user/", "C:\\intetpub\\files\users\\"); + + + + + + Add a new resource mapping. + + Request URI path + Disk path + + File names should not be included in URI or path. + + + + resources.Add("/files/", "C:\\intetpub\\files\\"); + + + absolutePath is not found. + + + + check if source contains any of the chars. + + string to check + Characters to fined + + + + + Go through all mappings and find requested Uri. + + Uri to get local path for. + Path if found; otherwise null. + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Gets a resource. + + Uri path to resource. + Resource + Uri contains forbidden characters. + + + Resource resource = resources.Get("/files/user/user.png"); + + + + + + Find all views in a folder/path. + + Absolute Uri path to files that should be found, can end with wild card. + Collection to add all view names to. + Uri contains forbidden characters. + + Find(" + + + + + Gets or sets forbidden characters. + + + Used to revoke access to any system files. + + + + + Gets or sets absolute path on disk, including file name. + + + + + Gets or sets relative file path. + + + + + Gets or sets Uri path, excluding file name + + + + + Used to send a response back to the client. + + + + Writes a object into a stream. + + + Important! ResponseWriter do not throw any exceptions. Instead it just logs them and + let them die peacefully. This is since the response writer is used from + catch blocks here and there. + + + + + + Sends response using the specified context. + + The context. + The response. + + + + Converts and sends a string. + + + + Encoding used to transfer string + + + + Send a body to the client + + Context containing the stream to use. + Body to send + + + + Send all headers to the client + + Response containing call headers. + Content used to send headers. + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Collection of headers. + + + + + Initializes a new instance of the class. + + Factory used to created headers. + + + + Adds a header + + + Will replace any existing header with the same name. + + header to add + header is null. + Header name cannot be null. + + + + Add a header. + + Header name + Header value + + Will try to parse the header and create a object. + + Header value is not correctly formatted. + name or value is null. + + + + Add a header. + + Header name + Header value + + Will try to parse the header and create a object. + + name or value is null. + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header + + header name. + header if found; otherwise null. + + + + Used to authenticate users + + + Authentication is requested by throwing + + + + + Implements basic authentication scheme. + + + + + Create a response that can be sent in the WWW-Authenticate header. + + Realm that the user should authenticate in + Not used by basic authentication + A WWW-Authenticate header. + Argument is null. + + + + An authentication response have been received from the web browser. + Check if it's correct + + Authorization header + Realm that should be authenticated + GET/POST/PUT/DELETE etc. + Authentication object that is stored for the request. A user class or something like that. + if authenticationHeader is invalid + If any of the paramters is empty or null. + + + + Gets authenticator scheme + + + + digest + + + + + Request implementation. + + + + + Initializes a new instance of the class. + + The method. + The path. + The version. + + + + Get a header + + Type that it should be cast to + Name of header + Header if found and casted properly; otherwise null. + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header. + + + + + + + Gets request URI. + + + + + Gets cookies. + + + + + Gets all uploaded files. + + + + + Gets query string and form parameters + + + + + Gets form parameters. + + + + + Gets query string. + + + + + Gets if request is an Ajax request. + + + + + Gets or sets connection header. + + + + + Gets or sets HTTP version. + + + + + Gets or sets HTTP method. + + + + + Gets requested URI. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets headers. + + + + + Gets body stream. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + Any specifically assigned value or Body stream length. + + + + + Initializes a new instance of the class. + + SSL protocol to use. + The socket. + The context. + Server certificate to use. + + + + Create stream used to send and receive bytes from the socket. + + Socket to wrap + Stream + Stream could not be created. + + + + Gets or sets client certificate. + + + + + Gets used protocol. + + + + + Gets or sets if client certificate should be used instead of server certificate. + + + + + A list of request cookies. + + + + + Let's copy all the cookies. + + value from cookie header. + + + + Initializes a new instance of the class. + + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + Name must be specified. + + + + Remove all cookies. + + + + + Remove a cookie from the collection. + + Name of cookie. + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier (null if not existing). + + + + + Parses query string + + + + + Parse a query string + + string to parse + A collection + reader is null. + + + + Parse a query string + + string to parse + A collection + queryString is null. + + + + Stores sessions in files. + + + All session parameters must be serializable. + + + + + Stores sessions in your favorite store + + + + + + + + Saves the specified session. + + The session. + + + + Touches the specified session + + Session id. + + Used to prevent sessions from expiring. + + + + + Loads a session + + Session id. + Session if found; otherwise null. + + + + Delete a session + + Id of session + + + + Saves the specified session. + + The session. + + + + Touches the specified session + + Session id. + + Used to prevent sessions from expiring. + + + + + Loads a session + + Session id. + Session if found; otherwise null. + + + + Create a HTTP response object. + + + + + Initializes a new instance of the class. + + HTTP Version. + HTTP status code. + Why the status code was selected. + Version must start with 'HTTP/' + + + + Initializes a new instance of the class. + + Context that the response will be sent through. + Request that the response is for. + Version must start with 'HTTP/' + + + + Redirect user. + + Where to redirect to. + + Any modifications after a redirect will be ignored. + + + + + Add a new header. + + + + + + + Add a new header. + + Header to add. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets a header. + + + + + + + Gets connection type. + + + + + Status code that is sent to the client. + + Default is + + + + Gets HTTP version. + + + Default is HTTP/1.1 + + + + + Information about why a specific status code was used. + + + + + Size of the body. MUST be specified before sending the header, + unless property Chunked is set to true. + + + Any specifically assigned value or Body stream length. + + + + + Kind of content in the body + + Default is text/html + + + + Gets or sets encoding + + + + + Gets cookies. + + + + + Gets body stream. + + + + + Gets headers. + + + + + Loads resources that are embedded in assemblies. + + + No locks used internally since all mappings are loaded during start up. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space that the resources exist in + + + + Add a specific resource. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space to root folder under (all name spaces below the specified one are considered as folders) + Name space and name of resource. + + + Add("/", Assembly.GetExecutingAssembly(), "MyApplication.Files", "Myapplication.Files.Images.MyImage.png"); + + + + + + Add resources. + + Path (Uri) requested by clients + Assembly that the resources exist in + Name of resource, including name space. + true if file was found (and has not previously been added); otherwise false. + + + + + + Add resources in a specific path (will not work with sub folders) + + Path (Uri) requested by clients + Assembly that the resources exist in + Name space to root folder under which all name spaces exists in, + true if any files was found; otherwise false. + + + Adds all views in the specified folder. Sub folders are not supported since it's hard to determine + with parts are the path and witch parts are the filename. Use to get support + for sub folders. + + + + + Add("/user/", typeof(MyController).Assembly, "YourProject.Users.Views"); + + + + + + Add resources in a folder and it's sub folder + + + + + + This method is not going to map files but keep the mapping and + try to look up views every time they are requested. This is the method + to use to add a resource folder that has sub folders. + + + + + + Tries to load file by using previously added paths. + + Uri path including file name + + + + + Checks if a resource exists in the specified directory + + Uri path to resource + true if resource was found; otherwise false. + + + if (resources.Exists("/files/user/user.png")) + Debug.WriteLine("Resource exists."); + + + + + + Load a resource. + + Uri of resource. + Resource if found and loaded; otherwise null. + + + + Find all views in a folder/path. + + Uri path + Collection to add all view names to. + + + + Loads all files in a resource directory + + + + + + Gets or sets assembly that the resource exists in. + + + + + Gets or sets resource name. + + + + + Gets or sets full name space path to resource. + + + + + Gets or sets if this file is for a certain content type. + + + + + Gets or sets full "virtual" Uri path, excluding file name. + + + + + Gets or sets assembly + + + + + Gets or sets name space root. + + + + + Gets or sets uri path. + + + + + Something unexpected went wrong. + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + Decodes URL encoded values. + + + + + + + Stream containing the content + Content type header + Stream encoding + Collection with all parameters. + Body format is invalid for the specified content type. + Failed to read all bytes from body stream. + + + + All content types that the decoder can parse. + + A collection of all content types that the decoder can handle. + + + + Parses and builds messages + + + The message factory takes care of building messages + from all end points. + + Since both message and packet protocols are used, the factory + hands out contexts to all end points. The context keeps a state + to be able to parse partial messages properly. + + + Each end point need to hand the context back to the message factory + when the client disconnects (or a message have been parsed). + + + + + + Initializes a new instance of the class. + + Factory used to create headers. + + + + Create a new message factory context. + + A new context. + + A context is used to parse messages from a specific endpoint. + + + + + Release a used factory context. + + + + + + A request have been received from one of the end points. + + + + + A response have been received from one of the end points. + + + + + Priority for log entries + + + + + + Very detailed logs to be able to follow the flow of the program. + + + + + Logs to help debug errors in the application + + + + + Information to be able to keep track of state changes etc. + + + + + Something did not go as we expected, but it's no problem. + + + + + Something that should not fail failed, but we can still keep + on going. + + + + + Something failed, and we cannot handle it properly. + + + + + Parses . + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Form parameters where form string arrays have been converted to real arrays. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Initializes a new instance of the class. + + Parse parameters from the this collection. + + + + Get a parameter. + + + + + + + Add a parameter + + Name of parameter, can contain a string array. + Value + + + ArrayParameterCollection array = new ArrayParameterCollection(); + array.Add("user[FirstName]", "Jonas"); + array.Add("user[FirstName]", "Arne"); + string firstName = array["user"]["FirstName"].Value; // "Arne" is returned + foreach (string value in array["user"]["FirstName"]) + Console.WriteLine(value); // each name is displayed. + + + + + + Checks if the specified parameter exists + + Parameter name. + true if found; otherwise false; + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Gets first value of an item. + + + String if found; otherwise null. + + + + Gets number of parameters. + + + + + Gets last value of an parameter. + + Parameter name + String if found; otherwise null. + + + + Assign properties from HTTP parameters. + + + + + Used to filter out properties. + + Filter handler. + Handler have already been set. + + + + Assign properties in the specified object. + + Object to fill. + Contains all parameters that should be assigned to the properties. + Properties was not found or value could not be converted. + Any parameter is null. + + + + Used to be able to filter properties + + Model having it's properties assigned + Property about to be assigned + Value to assign + true if value can be set; otherwise false. + + + + Failed to assign properties. + + + + + Initializes a new instance of the class. + + The property errors. + + + + Gets all errors during assignment. + + + Dictionary key is property name. + + + + + Requested resource may not be accessed. + + + Normally thrown after an authentication attempt have failed too many times. + + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + User needs to authenticate. + + + + + + + Initializes a new instance of the class. + + Exception description. + + + + Initializes a new instance of the class. + + Exception description. + Inner exception. + + + + First line in a response have been received + + + + + Gets or sets motivation to why the status code was used. + + + + + Gets or sets message status code + + + + + Gets or sets sip protocol version used. + + + + + Request context + + + Contains information about a HTTP request and where it came from. + + + + + Gets or sets http context. + + + + + Gets or sets http request. + + + + + Gets or sets http response. + + + + + Header for "Date" and "If-Modified-Since" + + + + The field value is an HTTP-date, as described in section 3.3.1 in RFC2616; + it MUST be sent in RFC 1123 [8]-date format. An example is + + Date: Tue, 15 Nov 1994 08:12:31 GMT + + Origin servers MUST include a Date header field in all + responses, except in these cases: + + If the response status code is 100 (Continue) or 101 (Switching + Protocols), the response MAY include a Date header field, at the server's + option. + If the response status code conveys a server error, e.g. 500 + (Internal Server Error) or 503 (Service Unavailable), and it is inconvenient + or impossible to generate a valid Date. + If the server does not have a clock that can provide a + reasonable approximation of the current time, its responses MUST NOT include + a Date header field. In this case, the rules in section 14.18.1 in RFC2616 + MUST be followed. + + + A received message that does not have a Date header field MUST + be assigned one by the recipient if the message will be cached by that + recipient or gatewayed via a protocol which requires a Date. An HTTP + implementation without a clock MUST NOT cache responses without revalidating + them on every use. An HTTP cache, especially a shared cache, SHOULD use a + mechanism, such as NTP [28], to synchronize its clock with a reliable + external standard. + Clients SHOULD only send a Date header field in messages that + include an entity-body, as in the case of the PUT and POST requests, and + even then it is optional. A client without a clock MUST NOT send a Date + header field in a request. + The HTTP-date sent in a Date header SHOULD NOT represent a date + and time subsequent to the generation of the message. It SHOULD represent + the best available approximation of the date and time of message generation, + unless the implementation has no means of generating a reasonably accurate + date and time. In theory, the date ought to represent the moment just before + the entity is generated. In practice, the date can be generated at any time + during the message origination without affecting its semantic value. + + + + + + Header name + + + + + Initializes a new instance of the class. + + Header name. + Name must not be empty. + + + + Initializes a new instance of the class. + + Header name. + Universal time. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets or sets date time. + + Should be in UTC. + + + + Gets header name + + + + + The Cache-Control general-header field is used to specify directives that + MUST be obeyed by all caching mechanisms along the request/response + chain. . + + + + The directives specify behavior intended to prevent caches from adversely + interfering with the request or response. These directives typically + override the default caching algorithms. Cache directives are + unidirectional in that the presence of a directive in a request does not + imply that the same directive is to be given in the response. + Note that HTTP/1.0 caches might not implement Cache-Control and + might only implement Pragma: no-cache (see section 14.32 in RFC2616). + Cache directives MUST be passed through by a proxy or gateway + application, regardless of their significance to that application, since the + directives might be applicable to all recipients along the request/response + chain. It is not possible to specify a cache- directive for a specific cache + + + When a directive appears without any 1#field-name parameter, the + directive applies to the entire request or response. When such a + directive appears with a 1#field-name parameter, it applies only to + the named field or fields, and not to the rest of the request or + response. This mechanism supports extensibility; implementations of + future versions of the HTTP protocol might apply these directives to + header fields not defined in HTTP/1.1. + + + The cache-control directives can be broken down into these general + categories: + + + Restrictions on what are cacheable; these may only be imposed by + the origin server. + + Restrictions on what may be stored by a cache; these may be + imposed by either the origin server or the user agent. + + Modifications of the basic expiration mechanism; these may be + imposed by either the origin server or the user agent. + + Controls over cache revalidation and reload; these may only be + imposed by a user agent. + + Control over transformation of entities. + + Extensions to the caching system. + + + + + + + + Header name + + + + + Gets header name + + + + + Authorization response + + + + A user agent that wishes to authenticate itself with a server-- + usually, but not necessarily, after receiving a 401 response--does + so by including an Authorization request-header field with the + request. The Authorization field value consists of credentials + containing the authentication information of the user agent for + the realm of the resource being requested. + + + Authorization = "Authorization" ":" credentials + + + HTTP access authentication is described in "HTTP Authentication: + Basic and Digest Access Authentication" [43]. If a request is + authenticated and a realm specified, the same credentials SHOULD + be valid for all other requests within this realm (assuming that + the authentication scheme itself does not require otherwise, such + as credentials that vary according to a challenge value or using + synchronized clocks). + When a shared cache (see section 13.7) receives a request + containing an Authorization field, it MUST NOT return the + corresponding response as a reply to any other request, unless one + of the following specific exceptions holds: + + + + If the response includes the "s-maxage" cache-control + directive, the cache MAY use that response in replying to a + subsequent request. But (if the specified maximum age has + passed) a proxy cache MUST first revalidate it with the origin + server, using the request-headers from the new request to allow + the origin server to authenticate the new request. (This is the + defined behavior for s-maxage.) If the response includes "s- + maxage=0", the proxy MUST always revalidate it before re-using + it. + + If the response includes the "must-revalidate" cache-control + directive, the cache MAY use that response in replying to a + subsequent request. But if the response is stale, all caches + MUST first revalidate it with the origin server, using the + request-headers from the new request to allow the origin server + to authenticate the new request. + + If the response includes the "public" cache-control directive, + it MAY be returned in reply to any subsequent request. + + + + + + + Name constant + + + + + Gets or sets authentication data. + + + + + Gets or sets authentication protocol. + + + + + Gets name of header. + + + + + Factory is used to create new logs in the system. + + + + + Assigns log factory being used. + + The log factory. + A factory have already been assigned. + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + + + A request have been received. + + + + + + + Initializes a new instance of the class. + + context that received the request. + Received request. + Response to send. + + + + Gets context that received the request. + + + Do not forget to set to true if you are sending + back a response manually through . + + + + + Gets or sets if the request have been handled. + + + The library will not attempt to send the response object + back to the client if this property is set to true. + + + + + Gets request object. + + + + + Gets response object. + + + + + Get or create components used in the web server framework + + + + + + + + Get or create a type. + + Type to create + Created type. + + Gets or creates types in the framework. + Check for more information on which + types the factory should contain. + + + + + Parses numerical values + + + + + Parse a header + + Name of header. + Reader containing value. + HTTP Header + Header value is not of the expected format. + + + + Contains parameters for HTTP headers. + + + + + Add a parameter + + name + value + + Existing parameter with the same name will be replaced. + + + + + Parse parameters. + + Parser containing buffer to parse. + A collection with all parameters (or just a empty collection). + Expected a value after equal sign. + + + + Parse parameters. + + Parser containing buffer to parse. + Parameter delimiter + A collection with all parameters (or just a empty collection). + Expected a value after equal sign. + + + + Returns a that represents the current . + + + A that represents the current . + + + + + Gets or sets a value + + parameter name + value if found; otherwise null. + + + + Component that should be registered in the container. + + + Register using all interfaces that is specified in this assembly. + + + + + Stream-based multipart handling. + + In this incarnation deals with an HttpInputStream as we are now using + IntPtr-based streams instead of byte []. In the future, we will also + send uploads above a certain threshold into the disk (to implement + limit-less HttpInputFiles). + + + Taken from HttpRequest in mono (http://www.mono-project.com) + + + + + Interface used to write to log files. + + + If you want to use the built in filtering mechanism, create a constructor + which takes one parameter, a . + + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Used to create all key types in the HTTP server. + + + Should have factory methods at least for the following types: + , , + , , + , , + , , + . + + Check the default implementations to see which constructor + parameters you will get. + + + HttpFactory.Add(typeof(IRequest), (type, args) => new MyRequest((string)args[0])); + + + + + + Initializes a new instance of the class. + + + + + Add a factory method for a type. + + Type to create + Method creating the type. + + + + Used to + + + + + + + Setup our singleton. + + + + + + We want to use a singleton, but we also want to be able + to let the developer to setup his own header factory. + Therefore we use this method to create our own factory only if the user + have not specified one. + + + + + Small method to create a message factory singleton and replace then default delegate method. + + + + + + + + Create a type. + + Type to create + Created type. + + + + Gets http factory for the current listener. + + + + + Delegate used to create a certain type + + Created type. + + Method must never fail. + + + + + Contains numerical value. + + + + + Initializes a new instance of the class. + + The name. + The value. + + + + Returns data formatted as a HTTP header value. + + + A that represents the current . + + + + + Gets value + + + + + Gets header name + + + + + Contents of a cookie header. + + + + + Initializes a new instance of the class. + + The collection. + collection is null. + + + + Gets cookie collection + + + + + Gets header name + + + + + Gets value as it would be sent back to client. + + + + + + Data decoded from a POST body. + + + + + Initializes a new instance of the class. + + + + + Gets or sets decoded files. + + + + + Gets or sets decoded parameters. + + + + + Collection of body decoders. + + + Body decoders are used to parse request body and convert it + into a and a . + + + + + Add another body decoder. + + + + + + Decode body stream + + Stream containing the content + Content type header + Stream encoding + Decoded data. + Body format is invalid for the specified content type. + Something unexpected failed. + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Returns an enumerator that iterates through a collection. + + + An object that can be used to iterate through the collection. + + 2 + + + + Gets number of decoders. + + + + + Credits and description: http://theinstructionlimit.com/?p=76 + + + Converted to .Net 2.0 + + + + + Type cached for fast property value modifications. + + + + + Get a property value. + + Instance to get value from. + Name of property. + Property value. + + + + Assign a value, try to convert it if it's not the same type as the property type. + + Object containing the property + Name of property + Value to convert and assign + Failed to find property. + Could not convert value type to property type. + + + + Assign value to a property + + Object containing the property + Name of property + Value to assign, must be of the same type as the property. + Failed to find property. + + + + Used to cache property information + + + + + Gets the property. + + The name. + + Failed to find property. + + + InvalidCastException. + + + + Get a property value. + + Instance to get value from. + Name of property. + Property value. + + + + Assign a value, try to convert it if it's not the same type as the property type. + + Object containing the property + Name of property + Value to convert and assign + Failed to find property. + Could not convert value type to property type. + + + + Assign value to a property + + Object containing the property + Name of property + Value to assign, must be of the same type as the property. + Failed to find property. + + + + Gets or sets member info + + + + + Gets or sets member type + + + + + A request have been received. + + + + + Initializes a new instance of the class. + + The request. + End point that the request was received from. + + + + End point that the message was received from. + + + + + Received request. + + + + + Creates a single message for one of the end points. + + + The factory is + + + + + Initializes a new instance of the class. + + The MSG factory. + The factory. + The parser. + + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + + 2 + + + + Received a header from parser + + + + + + + Will continue the parsing until nothing more can be parsed. + + buffer to parse + where to start in the buffer + number of bytes to process. + Position where parser stopped parsing. + Parsing failed. + + + + Reset parser. + + + Something failed, reset parser so it can start on a new request. + + + + + A request have been successfully parsed. + + + + + A response have been successfully parsed. + + + + + Client asks if he may continue. + + + If the body is too large or anything like that you should respond . + + + + + Used to notify about 100-continue header. + + + + + Initializes a new instance of the class. + + request that want to continue. + + + + Gets request that want to continue + + + + + Default log writer, writes everything to void (nowhere). + + + + + + The logging instance. + + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Write a entry needed when following through code during hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + This class writes to the console. + + + It colors the output depending on the log level + and includes a 3-level stack trace (in debug mode) + + + + + + Initializes a new instance of the class. + + Type being logged. + Log filter. + + + + Get color for the specified log level + + Level for the log entry + A for the level + + + + Write an entry + + Importance of the log message + The message. + + + + Write an entry that helps when debugging code. + + Log message + + + + Write an entry that helps when debugging code. + + Log message + Thrown exception to log. + + + + Write a entry needed when following through code during hard to find bugs. + + Log message + + + + Write a entry that helps when trying to find hard to find bugs. + + Log message + Thrown exception to log. + + + + Informational message, needed when helping customer to find a problem. + + Log message + + + + Informational message, needed when helping customer to find a problem. + + Log message + Thrown exception to log. + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + + + + Something is not as we expect, but the code can continue to run without any changes. + + Log message + Thrown exception to log. + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + + + + Something went wrong, but the application do not need to die. The current thread/request + cannot continue as expected. + + Log message + Thrown exception to log. + + + + Something went very wrong, application might not recover. + + Log message + + + + Something went very wrong, application might not recover. + + Log message + Thrown exception to log. + + + + Gets or sets type that the logger is for + + + + + Creates a console logger. + + + + + Initializes a new instance of the class. + + The filter. + + + + Create a new logger. + + Type that requested a logger. + Logger for the specified type; + + MUST ALWAYS return a logger. Return if no logging + should be used. + + + + + Cookies that should be set. + + + + + Adds a cookie in the collection. + + cookie to add + cookie is null + Name and Content must be specified. + + + + Copy a request cookie + + + When the cookie should expire + + + + Remove all cookies + + + + + Gets a collection enumerator on the cookie list. + + collection enumerator + + + + Returns an enumerator that iterates through the collection. + + + + A that can be used to iterate through the collection. + + 1 + + + + Gets the count of cookies in the collection. + + + + + Gets the cookie of a given identifier. + + Cookie if found; otherwise null. + + + + Provider returning user to be authenticated. + + + + + Lookups the specified user + + User name. + Typically web server domain name. + User if found; otherwise null. + + User name can basically be anything. For instance name entered by user when using + basic or digest authentication, or SID when using Windows authentication. + + + + + Gets the principal to use. + + Successfully authenticated user. + + + Invoked when a user have successfully been authenticated. + + + + + + + User information used during authentication process. + + + + + Gets or sets user name used during authentication. + + + + + Gets or sets unencrypted password. + + + Password as clear text. You could use instead if your passwords + are encrypted in the database. + + + + + Gets or sets HA1 hash. + + + + Digest authentication requires clear text passwords to work. If you + do not have that, you can store a HA1 hash in your database (which is part of + the Digest authentication process). + + + A HA1 hash is simply a Md5 encoded string: "UserName:Realm:Password". The quotes should + not be included. Realm is the currently requested Host (as in Request.Headers["host"]). + + + Leave the string as null if you are not using HA1 hashes. + + + + + + Provides authentication in the web server. + + + To initiate authentication you just need to throw a Una + + + + + Add a authenticator. + + + + + + Authenticate request. + + + + + Requires that a AuthorizationHeader have been sent by the client. If not, + request one by sending a WWW-Authentication header (can be generated by the Challenge method). + + Authorization header was not found in the request. + Requested authentication scheme is not supported. + + + + Create a challenge header (WWW-authenticate) + + Response that the authentication header should be added to + Realm that the user should authenticate in + WWW-Authenticate header. + + + Scheme can currently be basic or digest. Basic is not very safe, but easier to use. + Digest is quite safe. + + + + Requested scheme is not supported. + + + diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index 3faf935f..7a243147 100644 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -187,6 +187,18 @@ namespace TShockAPI [Description("This will announce a player's location on join")] public bool EnableGeoIP = false; + [Description("This will turn on a token requirement for the /status API endpoint.")] + public bool EnableTokenEndpointAuthentication = false; + + [Description("This is used when the API endpoint /status is queried.")] + public string ServerNickname = "TShock Server"; + + [Description("Enable/Disable the rest api.")] + public bool RestApiEnabled = false; + + [Description("This is the port which the rest api will listen on.")] + public int RestApiPort = 7878; + public static ConfigFile Read(string path) { if (!File.Exists(path)) diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs index 13fd0a20..ba4d3fd1 100644 --- a/TShockAPI/Properties/AssemblyInfo.cs +++ b/TShockAPI/Properties/AssemblyInfo.cs @@ -36,5 +36,5 @@ using System.Runtime.InteropServices; // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.3.0.0904")] -[assembly: AssemblyFileVersion("3.3.0.0904")] +[assembly: AssemblyVersion("3.3.2.0905")] +[assembly: AssemblyFileVersion("3.3.2.0905")] diff --git a/TShockAPI/Rest/Rest.cs b/TShockAPI/Rest/Rest.cs new file mode 100644 index 00000000..4c9c9e9f --- /dev/null +++ b/TShockAPI/Rest/Rest.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using HttpServer; +using HttpServer.Headers; +using Newtonsoft.Json; +using HttpListener = HttpServer.HttpListener; + +namespace Rests +{ + /// + /// Rest command delegate + /// + /// Parameters in the url + /// {x} in urltemplate + /// Response object or null to not handle request + public delegate object RestCommandD(RestVerbs verbs, IParameterCollection parameters); + public class Rest : IDisposable + { + readonly List commands = new List(); + HttpListener listener; + public IPAddress Ip { get; set; } + public int Port { get; set; } + + public Rest(IPAddress ip, int port) + { + Ip = ip; + Port = port; + } + public virtual void Start() + { + if (listener == null) + { + listener = HttpListener.Create(Ip, Port); + listener.RequestReceived += OnRequest; + listener.Start(int.MaxValue); + } + } + public void Start(IPAddress ip, int port) + { + Ip = ip; + Port = port; + Start(); + } + public virtual void Stop() + { + listener.Stop(); + } + + public void Register(string path, RestCommandD callback) + { + AddCommand(new RestCommand(path, callback)); + } + + public void Register(RestCommand com) + { + AddCommand(com); + } + + protected void AddCommand(RestCommand com) + { + commands.Add(com); + } + + protected virtual void OnRequest(object sender, RequestEventArgs e) + { + var obj = ProcessRequest(sender, e); + if (obj == null) + throw new NullReferenceException("obj"); + + var str = JsonConvert.SerializeObject(obj, Formatting.Indented); + e.Response.Connection.Type = ConnectionType.Close; + e.Response.Body.Write(Encoding.ASCII.GetBytes(str), 0, str.Length); + e.Response.Status = HttpStatusCode.OK; + return; + } + + protected virtual object ProcessRequest(object sender, RequestEventArgs e) + { + var uri = e.Request.Uri.AbsolutePath; + uri = uri.TrimEnd('/'); + + foreach (var com in commands) + { + var verbs = new RestVerbs(); + if (com.HasVerbs) + { + var match = Regex.Match(uri, com.UriVerbMatch); + if (!match.Success) + continue; + if ((match.Groups.Count - 1) != com.UriVerbs.Length) + continue; + + for (int i = 0; i < com.UriVerbs.Length; i++) + verbs.Add(com.UriVerbs[i], match.Groups[i + 1].Value); + } + else if (com.UriTemplate.ToLower() != uri.ToLower()) + { + continue; + } + + var obj = ExecuteCommand(com, verbs, e.Request.Parameters); + if (obj != null) + return obj; + + } + return new Dictionary { { "status", "404" }, { "error", "Specified API endpoint doesn't exist. Refer to the documentation for a list of valid endpoints." } }; + } + + protected virtual object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms) + { + return cmd.Callback(verbs, parms); + } + + #region Dispose + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (listener != null) + { + listener.Stop(); + listener = null; + } + } + } + ~Rest() + { + Dispose(false); + } + + #endregion + } +} diff --git a/TShockAPI/Rest/RestCommand.cs b/TShockAPI/Rest/RestCommand.cs new file mode 100644 index 00000000..82ca22b1 --- /dev/null +++ b/TShockAPI/Rest/RestCommand.cs @@ -0,0 +1,47 @@ +using System.Linq; +using System.Text.RegularExpressions; + +namespace Rests +{ + public class RestCommand + { + public string Name { get; protected set; } + public string UriTemplate { get; protected set; } + public string UriVerbMatch { get; protected set; } + public string[] UriVerbs { get; protected set; } + public RestCommandD Callback { get; protected set; } + public bool RequiesToken { get; set; } + + /// + /// + /// + /// Used for identification + /// Url template + /// Rest Command callback + public RestCommand(string name, string uritemplate, RestCommandD callback) + { + Name = name; + UriTemplate = uritemplate; + UriVerbMatch = string.Format("^{0}$", string.Join("([^/]*)", Regex.Split(uritemplate, "\\{[^\\{\\}]*\\}"))); + var matches = Regex.Matches(uritemplate, "\\{([^\\{\\}]*)\\}"); + UriVerbs = (from Match match in matches select match.Groups[1].Value).ToArray(); + Callback = callback; + RequiesToken = true; + } + /// + /// + /// + /// Url template + /// Rest Command callback + public RestCommand(string uritemplate, RestCommandD callback) + : this(string.Empty, uritemplate, callback) + { + + } + + public bool HasVerbs + { + get { return UriVerbs.Length > 0; } + } + } +} \ No newline at end of file diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs new file mode 100644 index 00000000..2b6a1f48 --- /dev/null +++ b/TShockAPI/Rest/RestManager.cs @@ -0,0 +1,360 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using HttpServer; +using Rests; +using Terraria; + +namespace TShockAPI +{ + + public class RestManager + { + private Rest Rest; + public RestManager(Rest rest) + { + Rest = rest; + } + + public void RegisterRestfulCommands() + { + Rest.Register(new RestCommand("/status", Status) { RequiesToken = false }); + Rest.Register(new RestCommand("/tokentest", TokenTest) { RequiesToken = true }); + + Rest.Register(new RestCommand("/users/read/{user}/info", UserInfo) { RequiesToken = true }); + Rest.Register(new RestCommand("/users/destroy/{user}", UserDestroy) { RequiesToken = true }); + Rest.Register(new RestCommand("/users/update/{user}", UserUpdate) { RequiesToken = true }); + + Rest.Register(new RestCommand("/bans/create", BanCreate) { RequiesToken = true }); + Rest.Register(new RestCommand("/bans/read/{user}/info", BanInfo) { RequiesToken = true }); + Rest.Register(new RestCommand("/bans/destroy/{user}", BanDestroy) { RequiesToken = true }); + + + Rest.Register(new RestCommand("/lists/players", UserList) { RequiesToken = true }); + + Rest.Register(new RestCommand("/world/read", WorldRead) { RequiesToken = true }); + Rest.Register(new RestCommand("/world/meteor", WorldMeteor) { RequiesToken = true }); + Rest.Register(new RestCommand("/world/bloodmoon/{bool}", WorldBloodmoon) { RequiesToken = true }); + //RegisterExamples(); + } + + #region RestMethods + + object TokenTest(RestVerbs verbs, IParameterCollection parameters) + { + return new Dictionary { { "status", "200" }, { "response", "Token is valid and was passed through correctly." } }; + } + + object Status(RestVerbs verbs, IParameterCollection parameters) + { + if (TShock.Config.EnableTokenEndpointAuthentication) + return new RestObject("403") { Error = "Server settings require a token for this API call." }; + + var activeplayers = Main.player.Where(p => p != null && p.active).ToList(); + string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name)); + + var ret = new RestObject("200"); + ret["name"] = TShock.Config.ServerNickname; + ret["port"] = Convert.ToString(TShock.Config.ServerPort); + ret["playercount"] = Convert.ToString(activeplayers.Count()); + ret["players"] = currentPlayers; + + return ret; + } + + #endregion + + #region RestUserMethods + + object UserList(RestVerbs verbs, IParameterCollection parameters) + { + var activeplayers = Main.player.Where(p => p != null && p.active).ToList(); + string currentPlayers = string.Join(", ", activeplayers.Select(p => p.name)); + var ret = new RestObject("200"); + ret["players"] = currentPlayers; + return ret; + } + + object UserUpdate(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var password = parameters["password"]; + var group = parameters["group"]; + + if (group == null && password == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "No parameters were passed."); + return returnBlock; + } + + var user = TShock.Users.GetUserByName(verbs["user"]); + if (user == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specefied user doesn't exist."); + return returnBlock; + } + + if (password != null) + { + TShock.Users.SetUserPassword(user, password); + returnBlock.Add("password-response", "Password updated successfully."); + } + + if (group != null) + { + TShock.Users.SetUserGroup(user, group); + returnBlock.Add("group-response", "Group updated successfully."); + } + + returnBlock.Add("status", "200"); + return returnBlock; + } + + object UserDestroy(RestVerbs verbs, IParameterCollection parameters) + { + var user = TShock.Users.GetUserByName(verbs["user"]); + if (user == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified user account does not exist." } }; + } + var returnBlock = new Dictionary(); + try + { + TShock.Users.RemoveUser(user); + } + catch (Exception) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specified user was unable to be removed."); + return returnBlock; + } + returnBlock.Add("status", "200"); + returnBlock.Add("response", "User deleted successfully."); + return returnBlock; + } + + object UserInfo(RestVerbs verbs, IParameterCollection parameters) + { + var user = TShock.Users.GetUserByName(verbs["user"]); + if (user == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified user account does not exist." } }; + } + + var returnBlock = new Dictionary(); + returnBlock.Add("status", "200"); + returnBlock.Add("group", user.Group); + returnBlock.Add("id", user.ID.ToString()); + return returnBlock; + } + + #endregion + + #region RestBanMethods + + object BanCreate(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var ip = parameters["ip"]; + var name = parameters["name"]; + var reason = parameters["reason"]; + + if (ip == null && name == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Required parameters were missing from this API endpoint."); + return returnBlock; + } + + if (ip == null) + { + ip = ""; + } + + if (name == null) + { + name = ""; + } + + if (reason == null) + { + reason = ""; + } + + try + { + TShock.Bans.AddBan(ip, name, reason); + } + catch (Exception) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specified ban was unable to be created."); + return returnBlock; + } + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Ban created successfully."); + return returnBlock; + } + + object BanDestroy(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + + var type = parameters["type"]; + if (type == null) + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + var ban = new DB.Ban(); + if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]); + else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]); + else + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + if (ban == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified ban does not exist." } }; + } + + try + { + TShock.Bans.RemoveBan(ban.IP); + } + catch (Exception) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "The specified ban was unable to be removed."); + return returnBlock; + } + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Ban deleted successfully."); + return returnBlock; + } + + object BanInfo(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + + var type = parameters["type"]; + if (type == null) + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + var ban = new DB.Ban(); + if (type == "ip") ban = TShock.Bans.GetBanByIp(verbs["user"]); + else if (type == "name") ban = TShock.Bans.GetBanByName(verbs["user"]); + else + { + returnBlock.Add("Error", "Invalid Type"); + return returnBlock; + } + + if (ban == null) + { + return new Dictionary { { "status", "400" }, { "error", "The specified ban does not exist." } }; + } + + returnBlock.Add("status", "200"); + returnBlock.Add("name", ban.Name); + returnBlock.Add("ip", ban.IP); + returnBlock.Add("reason", ban.Reason); + return returnBlock; + } + + #endregion + + #region RestWorldMethods + object WorldRead(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + returnBlock.Add("status", "200"); + returnBlock.Add("name", Main.worldName); + returnBlock.Add("size", Main.maxTilesX + "*" + Main.maxTilesY); + returnBlock.Add("time", Main.time.ToString()); + returnBlock.Add("daytime", Main.dayTime.ToString()); + returnBlock.Add("bloodmoon", Main.bloodMoon.ToString()); + returnBlock.Add("invasionsize", Main.invasionSize.ToString()); + return returnBlock; + } + + object WorldMeteor(RestVerbs verbs, IParameterCollection parameters) + { + WorldGen.dropMeteor(); + var returnBlock = new Dictionary(); + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Meteor has been spawned."); + return returnBlock; + } + + object WorldBloodmoon(RestVerbs verbs, IParameterCollection parameters) + { + var returnBlock = new Dictionary(); + var bloodmoonVerb = verbs["bool"]; + bool bloodmoon; + if (bloodmoonVerb == null) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "No parameter was passed."); + return returnBlock; + } + if (!bool.TryParse(bloodmoonVerb, out bloodmoon)) + { + returnBlock.Add("status", "400"); + returnBlock.Add("error", "Unable to parse parameter."); + return returnBlock; + } + Main.bloodMoon = bloodmoon; + returnBlock.Add("status", "200"); + returnBlock.Add("response", "Blood Moon has been set to " + bloodmoon.ToString()); + return returnBlock; + } + #endregion + + #region RestExampleMethods + + public void RegisterExamples() + { + Rest.Register(new RestCommand("/HelloWorld/name/{username}", UserTest) { RequiesToken = false }); + Rest.Register(new RestCommand("/wizard/{username}", Wizard) { RequiesToken = false }); + } + + //The Wizard example, for demonstrating the response convention: + object Wizard(RestVerbs verbs, IParameterCollection parameters) + { + var returnBack = new Dictionary(); + returnBack.Add("status", "200"); //Keep this in everything, 200 = ok, etc. Standard http status codes. + returnBack.Add("error", "(If this failed, you would have a different status code and provide the error object.)"); //And only include this if the status isn't 200 or a failure + returnBack.Add("Verified Wizard", "You're a wizard, " + verbs["username"]); //Outline any api calls and possible responses in some form of documentation somewhere + return returnBack; + } + + //http://127.0.0.1:8080/HelloWorld/name/{username}?type=status + object UserTest(RestVerbs verbs, IParameterCollection parameters) + { + var ret = new Dictionary(); + var type = parameters["type"]; + if (type == null) + { + ret.Add("Error", "Invalid Type"); + return ret; + } + if (type == "status") + { + ret.Add("Users", "Info here"); + return ret; + } + return null; + } + #endregion + } +} diff --git a/TShockAPI/Rest/RestObject.cs b/TShockAPI/Rest/RestObject.cs new file mode 100644 index 00000000..fcc21e6a --- /dev/null +++ b/TShockAPI/Rest/RestObject.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; + +namespace Rests +{ + [Serializable] + public class RestObject : Dictionary + { + public string Status + { + get { return this["status"]; } + set { this["status"] = value; } + } + public string Error + { + get { return this["error"]; } + set { this["error"] = value; } + } + public string Response + { + get { return this["response"]; } + set { this["response"] = value; } + } + + public RestObject(string status) + { + Status = status; + } + + /// + /// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove. + /// + /// + /// + /// Returns null if key does not exist. + public new string this[string key] + { + get + { + string ret; + if (TryGetValue(key, out ret)) + return ret; + return null; + } + set + { + if (!ContainsKey(key)) + { + if (value == null) + return; + Add(key, value); + } + else + { + if (value != null) + base[key] = value; + else + Remove(key); + } + } + } + } +} \ No newline at end of file diff --git a/TShockAPI/Rest/RestVerbs.cs b/TShockAPI/Rest/RestVerbs.cs new file mode 100644 index 00000000..bbad41d3 --- /dev/null +++ b/TShockAPI/Rest/RestVerbs.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace Rests +{ + [Serializable] + public class RestVerbs : Dictionary + { + /// + /// Gets value safely, if it does not exist, return null. Sets/Adds value safely, if null it will remove. + /// + /// + /// + /// Returns null if key does not exist. + public new string this[string key] + { + get + { + string ret; + if (TryGetValue(key, out ret)) + return ret; + return null; + } + set + { + if (!ContainsKey(key)) + { + if (value == null) + return; + Add(key, value); + } + else + { + if (value != null) + base[key] = value; + else + Remove(key); + } + } + } + } +} \ No newline at end of file diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs new file mode 100644 index 00000000..4d77c9b9 --- /dev/null +++ b/TShockAPI/Rest/SecureRest.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using HttpServer; +using TShockAPI; + +namespace Rests +{ + /// + /// + /// + /// Username to verify + /// Password to verify + /// Returning a restobject with a null error means a successful verification. + public delegate RestObject VerifyD(string username, string password); + public class SecureRest : Rest + { + public Dictionary Tokens { get; protected set; } + public event VerifyD Verify; + public SecureRest(IPAddress ip, int port) + : base(ip, port) + { + Tokens = new Dictionary(); + Register(new RestCommand("/token/create/{username}/{password}", NewToken) { RequiesToken = false }); + Register(new RestCommand("/token/destroy/{token}", DestroyToken) { RequiesToken = true }); + } + + object DestroyToken(RestVerbs verbs, IParameterCollection parameters) + { + var token = verbs["token"]; + try + { + Tokens.Remove(token); + } + catch (Exception) + { + return new Dictionary { { "status", "400" }, { "error", "The specified token queued for destruction failed to be deleted." } }; + } + return new Dictionary { { "status", "200" }, { "response", "Requested token was successfully destroyed." } }; + } + + object NewToken(RestVerbs verbs, IParameterCollection parameters) + { + var user = verbs["username"]; + var pass = verbs["password"]; + + RestObject obj = null; + if (Verify != null) + obj = Verify(user, pass); + + if (obj == null) + obj = new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." }; + + if (obj.Error != null) + return obj; + + string hash; + var rand = new Random(); + var randbytes = new byte[32]; + do + { + rand.NextBytes(randbytes); + hash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2")); + } while (Tokens.ContainsKey(hash)); + + Tokens.Add(hash, user); + + obj["token"] = hash; + return obj; + } + + + + protected override object ExecuteCommand(RestCommand cmd, RestVerbs verbs, IParameterCollection parms) + { + if (cmd.RequiesToken) + { + var strtoken = parms["token"]; + if (strtoken == null) + return new Dictionary { { "status", "401" }, { "error", "Not authorized. The specified API endpoint requires a token." } }; + + object token; + if (!Tokens.TryGetValue(strtoken, out token)) + return new Dictionary { { "status", "403" }, { "error", "Not authorized. The specified API endpoint requires a token, but the provided token was not valid." } }; + } + return base.ExecuteCommand(cmd, verbs, parms); + } + } +} diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 89038817..bebb5e35 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -34,9 +34,12 @@ using System.IO; using System.Net; using System.Reflection; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using Community.CsharpSqlite.SQLiteClient; +using HttpServer; using MySql.Data.MySqlClient; +using Rests; using Terraria; using TerrariaAPI; using TerrariaAPI.Hooks; @@ -67,6 +70,8 @@ namespace TShockAPI public static bool OverridePort; public static PacketBufferer PacketBuffer; public static MaxMind.GeoIPCountry Geo; + public static SecureRest RestApi; + public static RestManager RestManager; /// /// Called after TShock is initialized. Useful for plugins that needs hooks before tshock but also depend on tshock being loaded. @@ -172,8 +177,15 @@ namespace TShockAPI Regions = new RegionManager(DB); Itembans = new ItemManager(DB); RememberedPos = new RemeberedPosManager(DB); - if (Config.EnableGeoIP) - Geo = new MaxMind.GeoIPCountry(Path.Combine(SavePath, "GeoIP.dat")); + RestApi = new SecureRest(IPAddress.Any, 8080); + RestApi.Verify += RestApi_Verify; + RestApi.Port = Config.RestApiPort; + RestManager = new RestManager(RestApi); + RestManager.RegisterRestfulCommands(); + + var geoippath = Path.Combine(SavePath, "GeoIP.dat"); + if (Config.EnableGeoIP && File.Exists(geoippath)) + Geo = new MaxMind.GeoIPCountry(geoippath); Log.ConsoleInfo(string.Format("TShock Version {0} ({1}) now running.", Version, VersionCodename)); @@ -209,6 +221,27 @@ namespace TShockAPI } } + RestObject RestApi_Verify(string username, string password) + { + var userAccount = TShock.Users.GetUserByName(username); + if (userAccount == null) + { + return new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." }; + } + + if (Tools.HashPassword(password).ToUpper() != userAccount.Password.ToUpper()) + { + return new RestObject("401") { Error = "Invalid username/password combination provided. Please re-submit your query with a correct pair." }; + } + + if (!Tools.GetGroup(userAccount.Group).HasPermission("api") && userAccount.Group != "superadmin") + { + return new RestObject("403") { Error = "Although your account was successfully found and identified, your account lacks the permission required to use the API. (api)" }; + } + + return new RestObject("200") { Response = "Successful login" }; //Maybe return some user info too? + } + public override void DeInitialize() { GameHooks.PostInitialize -= OnPostInit; @@ -226,6 +259,7 @@ namespace TShockAPI Console.WriteLine("Thanks for using TShock! Process ID file is now being destroyed."); File.Delete(Path.Combine(SavePath, "tshock.pid")); } + RestApi.Dispose(); //RconHandler.ShutdownAllThreads(); } @@ -276,6 +310,7 @@ namespace TShockAPI if (IPAddress.TryParse(parms[++i], out ip)) { Netplay.serverListenIP = ip; + RestApi.Ip = ip; Console.Write("Using IP: {0}", ip); } else @@ -353,6 +388,8 @@ namespace TShockAPI AuthToken = 0; } Regions.ReloadAllRegions(); + if (Config.RestApiEnabled) + RestApi.Start(); } @@ -625,7 +662,7 @@ namespace TShockAPI NetMessage.SendData((int)PacketTypes.TimeSet, -1, -1, "", 0, 0, Main.sunModY, Main.moonModY); NetMessage.syncPlayers(); - if (Config.EnableGeoIP) + if (Config.EnableGeoIP && Geo != null) { var code = Geo.TryGetCountryCode(IPAddress.Parse(player.IP)); player.Country = code == null ? "N/A" : MaxMind.GeoIPCountry.GetCountryNameByCode(code); diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 523752e5..5a4d895b 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -52,6 +52,9 @@ False ..\SqlBins\Community.CsharpSqlite.SQLiteClient.dll + + ..\HttpBins\HttpServer.dll + False ..\SqlBins\MySql.Data.dll @@ -121,6 +124,12 @@ True Resources.resx + + + + + + @@ -177,7 +186,7 @@ - +