diff --git a/DBEditor/CommandList.cs b/DBEditor/CommandList.cs
index 93ed1064..1318fa5c 100644
--- a/DBEditor/CommandList.cs
+++ b/DBEditor/CommandList.cs
@@ -36,6 +36,7 @@ namespace TShockDBEditor
CommandList.Add("kill");
CommandList.Add("butcher");
CommandList.Add("item");
+ CommandList.Add("clearitems");
CommandList.Add("heal");
CommandList.Add("whisper");
CommandList.Add("annoy");
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/Commands.cs b/TShockAPI/Commands.cs
index 9fc50466..fed39020 100644
--- a/TShockAPI/Commands.cs
+++ b/TShockAPI/Commands.cs
@@ -1,4 +1,4 @@
-/*
+/*
TShock, a server mod for Terraria
Copyright (C) 2011 The TShock Team
@@ -18,7 +18,7 @@ along with this program. If not, see .
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Drawing;
+
using System.IO;
using System.Linq;
using System.Net;
@@ -36,7 +36,7 @@ namespace TShockAPI
public string Message { get; private set; }
public TSPlayer Player { get; private set; }
///
- /// Parameters passed to the arguement. Does not include the command name.
+ /// Parameters passed to the arguement. Does not include the command name.
/// IE '/kick "jerk face"' will only have 1 argument
///
public List Parameters { get; private set; }
@@ -137,6 +137,7 @@ namespace TShockAPI
add(Permissions.tp, Spawn, "spawn");
add(Permissions.tp, TP, "tp");
add(Permissions.tphere, TPHere, "tphere");
+ add(Permissions.tphere, SendWarp, "sendwarp", "sw");
add(Permissions.warp, UseWarp, "warp");
add(Permissions.managewarp, SetWarp, "setwarp");
add(Permissions.managewarp, DeleteWarp, "delwarp");
@@ -151,6 +152,7 @@ namespace TShockAPI
add(Permissions.cfg, ShowConfiguration, "showconfig");
add(Permissions.cfg, ServerPassword, "serverpassword");
add(Permissions.cfg, Save, "save");
+ add(Permissions.cfg, Settle, "settle");
add(Permissions.cfg, MaxSpawns, "maxspawns");
add(Permissions.cfg, SpawnRate, "spawnrate");
add(Permissions.time, Time, "time");
@@ -164,6 +166,7 @@ namespace TShockAPI
add(null, AuthToken, "auth");
add(null, ThirdPerson, "me");
add(null, PartyChat, "p");
+ add(null, Motd, "motd");
add(null, Rules, "rules");
add(Permissions.logs, DisplayLogs, "displaylogs");
ChatCommands.Add(new Command(PasswordUser, "password") { DoLog = false });
@@ -181,6 +184,7 @@ namespace TShockAPI
add(Permissions.butcher, Butcher, "butcher");
add(Permissions.item, Item, "item", "i");
add(Permissions.item, Give, "give");
+ add(Permissions.clearitems, ClearItems, "clearitems");
add(Permissions.heal, Heal, "heal");
add(Permissions.buff, Buff, "buff");
add(Permissions.buffplayer, GBuff, "gbuff", "buffplayer");
@@ -350,7 +354,6 @@ namespace TShockAPI
private static void PasswordUser(CommandArgs args)
{
-
try
{
if (args.Player.IsLoggedIn && args.Parameters.Count == 2)
@@ -430,6 +433,13 @@ namespace TShockAPI
// return;
//}
+ // This guy needs to be here so that people don't get exceptions when they type /user
+ if (args.Parameters.Count < 1)
+ {
+ args.Player.SendMessage("Invalid user syntax. Try /user help.", Color.Red);
+ return;
+ }
+
string subcmd = args.Parameters[0];
// Add requires a username:password pair/ip address and a group specified.
@@ -899,7 +909,6 @@ namespace TShockAPI
Tools.ForceKickAll("Server shutting down for update!");
WorldGen.saveWorld();
Netplay.disconnect = true;
-
}
#endregion Server Maintenence Commands
@@ -918,7 +927,7 @@ namespace TShockAPI
int penis57 = Main.rand.Next(Main.maxTilesX - 50) + 100;
penis57 *= 0x10;
int penis58 = Main.rand.Next((int)(Main.maxTilesY * 0.05)) * 0x10;
- PointF vector = new PointF(penis57, penis58);
+ Vector2 vector = new Vector2(penis57, penis58);
float speedX = Main.rand.Next(-100, 0x65);
float speedY = Main.rand.Next(200) + 100;
float penis61 = (float)Math.Sqrt(((speedX * speedX) + (speedY * speedY)));
@@ -1202,6 +1211,42 @@ namespace TShockAPI
}
}
+ private static void SendWarp(CommandArgs args)
+ {
+ if (args.Parameters.Count < 2)
+ {
+ args.Player.SendMessage("Invalid syntax! Proper syntax: /sendwarp [player] [warpname]", Color.Red);
+ return;
+ }
+
+ var foundplr = Tools.FindPlayer(args.Parameters[0]);
+ if (foundplr.Count == 0)
+ {
+ args.Player.SendMessage("Invalid player!", Color.Red);
+ return;
+ }
+ else if (foundplr.Count > 1)
+ {
+ args.Player.SendMessage(string.Format("More than one ({0}) player matched!", args.Parameters.Count), Color.Red);
+ return;
+ }
+ string warpName = String.Join(" ", args.Parameters[1]);
+ var warp = TShock.Warps.FindWarp(warpName);
+ var plr = foundplr[0];
+ if (warp.WarpPos != Vector2.Zero)
+ {
+ if (plr.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3))
+ {
+ plr.SendMessage(string.Format("{0} Warped you to {1}", args.Player.Name, warpName), Color.Yellow);
+ args.Player.SendMessage(string.Format("You warped {0} to {1}.", plr.Name, warpName), Color.Yellow);
+ }
+ }
+ else
+ {
+ args.Player.SendMessage("Specified warp not found", Color.Red);
+ }
+ }
+
private static void SetWarp(CommandArgs args)
{
if (args.Parameters.Count > 0)
@@ -1327,7 +1372,7 @@ namespace TShockAPI
{
string warpName = String.Join(" ", args.Parameters);
var warp = TShock.Warps.FindWarp(warpName);
- if (warp.WarpPos != PointF.Empty)
+ if (warp.WarpPos != Vector2.Zero)
{
if (args.Player.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3))
args.Player.SendMessage("Warped to " + warpName, Color.Yellow);
@@ -1337,7 +1382,6 @@ namespace TShockAPI
args.Player.SendMessage("Specified warp not found", Color.Red);
}
}
-
}
#endregion Teleport Commands
@@ -1538,9 +1582,21 @@ namespace TShockAPI
SaveWorld.Start();
}
- private static void MaxSpawns(CommandArgs args)
+ private static void Settle(CommandArgs args)
{
+ if (Liquid.panicMode)
+ {
+ args.Player.SendMessage("Liquid is already settling!", Color.Red);
+ return;
+ }
+ Liquid.StartPanic();
+ Tools.Broadcast("Settling all liquids...");
+
+ }
+
+ private static void MaxSpawns(CommandArgs args)
+ {
if (args.Parameters.Count != 1)
{
args.Player.SendMessage("Invalid syntax! Proper syntax: /maxspawns ", Color.Red);
@@ -1688,7 +1744,6 @@ namespace TShockAPI
}
switch (cmd)
{
-
case "name":
{
{
@@ -1697,7 +1752,6 @@ namespace TShockAPI
}
break;
}
-
case "set":
{
int choice = 0;
@@ -1718,7 +1772,7 @@ namespace TShockAPI
{
if (args.Parameters.Count > 1)
{
- if (!args.Player.TempPoints.Any(p => p == PointF.Empty))
+ if (!args.Player.TempPoints.Any(p => p == Point.Zero))
{
string regionName = String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1));
var x = Math.Min(args.Player.TempPoints[0].X, args.Player.TempPoints[1].X);
@@ -1728,8 +1782,8 @@ namespace TShockAPI
if (TShock.Regions.AddRegion(x, y, width, height, regionName, Main.worldID.ToString()))
{
- args.Player.TempPoints[0] = Point.Empty;
- args.Player.TempPoints[1] = Point.Empty;
+ args.Player.TempPoints[0] = Point.Zero;
+ args.Player.TempPoints[1] = Point.Zero;
args.Player.SendMessage("Set region " + regionName, Color.Yellow);
}
else
@@ -1788,8 +1842,8 @@ namespace TShockAPI
}
case "clear":
{
- args.Player.TempPoints[0] = Point.Empty;
- args.Player.TempPoints[1] = Point.Empty;
+ args.Player.TempPoints[0] = Point.Zero;
+ args.Player.TempPoints[1] = Point.Zero;
args.Player.SendMessage("Cleared temp area", Color.Yellow);
args.Player.AwaitingTempPoint = 0;
break;
@@ -1950,6 +2004,62 @@ namespace TShockAPI
args.Player.SendMessage("Invalid syntax! Proper syntax: /region info [name]", Color.Red);
}
+ break;
+ }
+ case "resize":
+ case "expand":
+ {
+ if (args.Parameters.Count == 4)
+ {
+ int direction;
+ switch (args.Parameters[3])
+ {
+ case "u":
+ case "up":
+ {
+ direction = 0;
+ break;
+ }
+ case "r":
+ case "right":
+ {
+ direction = 1;
+ break;
+ }
+ case "d":
+ case "down":
+ {
+ direction = 2;
+ break;
+ }
+ case "l":
+ case "left":
+ {
+ direction = 3;
+ break;
+ }
+ default:
+ {
+ direction = -1;
+ break;
+ }
+ }
+ int addAmount;
+ int.TryParse(args.Parameters[2], out addAmount);
+ if (TShock.Regions.resizeRegion(args.Parameters[1], addAmount, direction))
+ {
+ args.Player.SendMessage("Region Resized Successfully!", Color.Yellow);
+ TShock.Regions.ReloadAllRegions();
+ }
+ else
+ {
+ args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize [regionname] [u/d/l/r] [amount]", Color.Red);
+ }
+ }
+ else
+ {
+ args.Player.SendMessage("Invalid syntax! Proper syntax: /region resize [regionname] [u/d/l/r] [amount]1", Color.Red);
+ }
break;
}
case "help":
@@ -1960,10 +2070,10 @@ namespace TShockAPI
args.Player.SendMessage("/region name (provides region name)", Color.Yellow);
args.Player.SendMessage("/region delete [name] /region clear (temporary region)", Color.Yellow);
args.Player.SendMessage("/region allow [name] [regionname]", Color.Yellow);
+ args.Player.SendMessage("/region resize [regionname] [u/d/l/r] [amount]", Color.Yellow);
break;
}
}
-
}
#endregion World Protection Commands
@@ -2117,6 +2227,11 @@ namespace TShockAPI
args.Player.SendMessage("You are not in a party!", 255, 240, 20);
}
}
+
+ private static void Motd(CommandArgs args)
+ {
+ Tools.ShowFileToUser(args.Player, "motd.txt");
+ }
private static void Rules(CommandArgs args)
{
@@ -2185,6 +2300,7 @@ namespace TShockAPI
(new Thread(ply.Whoopie)).Start(annoy);
}
}
+
#endregion General Commands
#region Cheat Commands
@@ -2359,6 +2475,50 @@ namespace TShockAPI
}
}
+ public static void ClearItems(CommandArgs args)
+ {
+
+ int radius = 50;
+ if (args.Parameters.Count > 0)
+ {
+
+ if (args.Parameters[0].ToLower() == "all")
+ {
+
+ radius = Int32.MaxValue / 16;
+
+ }
+ else
+ {
+
+ try
+ {
+
+ radius = Convert.ToInt32(args.Parameters[0]);
+
+ }
+ catch (Exception) { args.Player.SendMessage("Please either enter the keyword \"all\", or the block radius you wish to delete all items from.", Color.Red); return; }
+
+ }
+
+ }
+ int count = 0;
+ for (int i = 0; i < 200; i++)
+ {
+
+ if ((Math.Sqrt(Math.Pow(Main.item[i].position.X - args.Player.X, 2) + Math.Pow(Main.item[i].position.Y - args.Player.Y, 2)) < radius * 16) && (Main.item[i].active))
+ {
+
+ Main.item[i].active = false;
+ NetMessage.SendData(0x15, -1, -1, "", i, 0f, 0f, 0f, 0);
+ count++;
+ }
+
+ }
+ args.Player.SendMessage("All " + count.ToString() + " items within a radius of " + radius.ToString() + " have been deleted.");
+
+ }
+
private static void Heal(CommandArgs args)
{
TSPlayer playerToHeal;
@@ -2563,8 +2723,10 @@ namespace TShockAPI
args.Player.SendMessage("Unknown plant!", Color.Red);
return;
}
- args.Player.SendMessage("You have grown a " + name, Color.Green);
+ args.Player.SendTileSquare(x, y);
+ args.Player.SendMessage("Tried to grow a " + name, Color.Green);
}
+
#endregion Cheat Comamnds
}
}
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/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs
index 70e444d2..1fd408a3 100644
--- a/TShockAPI/DB/GroupManager.cs
+++ b/TShockAPI/DB/GroupManager.cs
@@ -154,8 +154,10 @@ namespace TShockAPI.DB
permissions.AddRange(group.permissions.Where(s => !permissions.Contains(s)));
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", permissions), name) != 0)
+ {
message = "Group " + name + " has been modified successfully.";
-
+ group.SetPermission( permissions );
+ }
return message;
}
@@ -168,11 +170,13 @@ namespace TShockAPI.DB
var group = Tools.GetGroup(name);
//Only get permissions that exist in the group.
- var newperms = permissions.Where(s => group.permissions.Contains(s));
+ var newperms = group.permissions.Except( permissions );
if (database.Query("UPDATE GroupList SET Commands=@0 WHERE GroupName=@1", String.Join(",", newperms), name) != 0)
+ {
message = "Group " + name + " has been modified successfully.";
-
+ group.SetPermission( newperms.ToList() );
+ }
return message;
}
diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs
index cd4c2faf..5c78241b 100644
--- a/TShockAPI/DB/RegionManager.cs
+++ b/TShockAPI/DB/RegionManager.cs
@@ -20,7 +20,7 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.CodeAnalysis;
-using System.Drawing;
+
using System.IO;
using System.Linq;
using System.Xml;
@@ -378,6 +378,68 @@ namespace TShockAPI.DB
{
return MergedIDs.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
+
+ public bool resizeRegion(string regionName, int addAmount, int direction)
+ {
+ //0 = up
+ //1 = right
+ //2 = down
+ //3 = left
+ int X = 0;
+ int Y = 0;
+ int height = 0;
+ int width = 0;
+ try
+ {
+ using (var reader = database.QueryReader("SELECT X1, Y1, height, width FROM Regions WHERE RegionName=@0 AND WorldID=@1", regionName, Main.worldID.ToString()))
+ {
+ if (reader.Read())
+ X = reader.Get("X1");
+ width = reader.Get("width");
+ Y = reader.Get("Y1");
+ height = reader.Get("height");
+ }
+ if (!(direction == 0))
+ {
+ if (!(direction == 1))
+ {
+ if (!(direction == 2))
+ {
+ if (!(direction == 3))
+ {
+ return false;
+ }
+ else
+ {
+ X -= addAmount;
+ width += addAmount;
+ }
+ }
+ else
+ {
+ height += addAmount;
+ }
+ }
+ else
+ {
+ width += addAmount;
+ }
+ }
+ else
+ {
+ Y -= addAmount;
+ height += addAmount;
+ }
+ int q = database.Query("UPDATE Regions SET X1 = @0, Y1 = @1, width = @2, height = @3 WHERE RegionName = @4 AND WorldID=@5", X, Y, width, height, regionName, Main.worldID.ToString());
+ if (q > 0)
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ return false;
+ }
public bool RemoveUser(string regionName, string userName)
{
diff --git a/TShockAPI/DB/RememberPosManager.cs b/TShockAPI/DB/RememberPosManager.cs
index 4bb546dc..71a9bc5e 100644
--- a/TShockAPI/DB/RememberPosManager.cs
+++ b/TShockAPI/DB/RememberPosManager.cs
@@ -18,7 +18,7 @@ along with this program. If not, see .
using System;
using System.Data;
-using System.Drawing;
+
using MySql.Data.MySqlClient;
using Terraria;
@@ -43,7 +43,7 @@ namespace TShockAPI.DB
creator.EnsureExists(table);
}
- public PointF GetLeavePos(string name, string IP)
+ public Vector2 GetLeavePos(string name, string IP)
{
try
{
@@ -51,7 +51,7 @@ namespace TShockAPI.DB
{
if (reader.Read())
{
- return new PointF(reader.Get("X"), reader.Get("Y"));
+ return new Vector2(reader.Get("X"), reader.Get("Y"));
}
}
}
@@ -60,12 +60,12 @@ namespace TShockAPI.DB
Log.Error(ex.ToString());
}
- return new PointF();
+ return new Vector2();
}
public void InsertLeavePos(string name, string IP, int X, int Y)
{
- if (GetLeavePos(name, IP) == PointF.Empty)
+ if (GetLeavePos(name, IP) == Vector2.Zero)
{
try
{
diff --git a/TShockAPI/DB/WarpsManager.cs b/TShockAPI/DB/WarpsManager.cs
index d265caa9..c1599e0b 100644
--- a/TShockAPI/DB/WarpsManager.cs
+++ b/TShockAPI/DB/WarpsManager.cs
@@ -19,7 +19,7 @@ along with this program. If not, see .
using System;
using System.Collections.Generic;
using System.Data;
-using System.Drawing;
+
using System.IO;
using System.Xml;
using MySql.Data.MySqlClient;
@@ -173,11 +173,11 @@ namespace TShockAPI.DB
{
try
{
- return new Warp(new PointF(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), reader.Get("Private"));
+ return new Warp(new Vector2(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), reader.Get("Private"));
}
catch
{
- return new Warp(new PointF(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), "0");
+ return new Warp(new Vector2(reader.Get("X"), reader.Get("Y")), reader.Get("WarpName"), reader.Get("WorldID"), "0");
}
}
}
@@ -247,12 +247,12 @@ namespace TShockAPI.DB
public class Warp
{
- public PointF WarpPos { get; set; }
+ public Vector2 WarpPos { get; set; }
public string WarpName { get; set; }
public string WorldWarpID { get; set; }
public string Private { get; set; }
- public Warp(PointF warppos, string name, string worldid, string hidden)
+ public Warp(Vector2 warppos, string name, string worldid, string hidden)
{
WarpPos = warppos;
WarpName = name;
@@ -262,7 +262,7 @@ namespace TShockAPI.DB
public Warp()
{
- WarpPos = PointF.Empty;
+ WarpPos = Vector2.Zero;
WarpName = null;
WorldWarpID = string.Empty;
Private = "0";
diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs
index 52f5c011..66d7ac8b 100644
--- a/TShockAPI/Extensions/DbExt.cs
+++ b/TShockAPI/Extensions/DbExt.cs
@@ -52,6 +52,20 @@ namespace TShockAPI.DB
}
}
+ public static QueryResult QueryReaderDict(this IDbConnection olddb, string query, Dictionary values)
+ {
+ var db = olddb.CloneEx();
+ db.Open();
+ using (var com = db.CreateCommand())
+ {
+ com.CommandText = query;
+ foreach(var kv in values)
+ com.AddParameter("@" + kv.Key, kv.Value);
+
+ return new QueryResult(db, com.ExecuteReader());
+ }
+ }
+
public static IDbDataParameter AddParameter(this IDbCommand command, string name, object data)
{
var parm = command.CreateParameter();
@@ -157,10 +171,14 @@ namespace TShockAPI.DB
public bool Read()
{
+ if (Reader == null)
+ return false;
return Reader.Read();
}
public T Get(string column)
{
+ if (Reader == null)
+ return default(T);
return Reader.Get(Reader.GetOrdinal(column));
}
}
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index d6341b86..62d0fcb1 100644
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -18,13 +18,13 @@ along with this program. If not, see .
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Drawing;
+
using System.IO;
using System.Text;
using Terraria;
-using TerrariaAPI;
+
using TShockAPI.Net;
-using XNAHelpers;
+using System.IO.Streams;
namespace TShockAPI
{
@@ -349,6 +349,13 @@ namespace TShockAPI
args.Player.SendTileSquare(x, y);
return true;
}
+ if (type == 1 && tiletype == 21 && Tools.MaxChests())
+ {
+ args.Player.SendMessage("Reached world's max chest limit, unable to place more!", Color.Red);
+ Log.Info("Reached world's chest limit, unable to place more.");
+ args.Player.SendTileSquare(x, y);
+ return true;
+ }
}
if (!args.Player.Group.HasPermission(Permissions.editspawn) && !TShock.Regions.CanBuild(x, y, args.Player) && TShock.Regions.InArea(x, y))
{
@@ -393,9 +400,9 @@ namespace TShockAPI
if (type == 0 && BlacklistTiles[Main.tile[x, y].type] && args.Player.Active)
{
args.Player.TileThreshold++;
- var coords = new PointF(x, y);
+ var coords = new Vector2(x, y);
if (!args.Player.TilesDestroyed.ContainsKey(coords))
- args.Player.TilesDestroyed.Add(coords, Main.tile[x, y]);
+ args.Player.TilesDestroyed.Add(coords, Main.tile[x, y].Data);
}
if ((DateTime.UtcNow - args.Player.LastExplosive).TotalMilliseconds < 1000)
@@ -480,12 +487,18 @@ namespace TShockAPI
return true;
}
- if (type == 23 && (vely == 0f || velx == 0f)) //float.IsNaN((float)Math.Sqrt((double)(velx * velx + vely * vely))))
+ if (type == 23)
{
- Tools.HandleGriefer(args.Player, TShock.Config.ProjectileAbuseReason);
- return true;
+ if (velx == 0f && vely == 0f && dmg == 99)
+ {
+ Tools.HandleGriefer(args.Player, TShock.Config.ProjectileAbuseReason);
+ return true;
+ }
+ else if (velx == 0f || vely == 0f)
+ return true;
}
+
if (type == 29 || type == 28 || type == 37)
{
Log.Debug(string.Format("Explosive(PlyXY:{0}_{1}, Type:{2})", args.Player.TileX, args.Player.TileY, type));
diff --git a/TShockAPI/Group.cs b/TShockAPI/Group.cs
index a7fbddb3..c089ff16 100644
--- a/TShockAPI/Group.cs
+++ b/TShockAPI/Group.cs
@@ -73,6 +73,14 @@ namespace TShockAPI
{
permissions.Add(permission);
}
+ public void SetPermission( List permission)
+ {
+ permissions.Clear();
+ foreach( string s in permission )
+ {
+ permissions.Add( s );
+ }
+ }
}
public class SuperAdminGroup : Group
diff --git a/TShockAPI/Net/BaseMsg.cs b/TShockAPI/Net/BaseMsg.cs
index ed41cf71..77fa041c 100644
--- a/TShockAPI/Net/BaseMsg.cs
+++ b/TShockAPI/Net/BaseMsg.cs
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
+using System.IO.Streams;
using System.Linq;
using System.Text;
-using TerrariaAPI;
-using XNAHelpers;
+
+using System.IO.Streams;
namespace TShockAPI.Net
{
diff --git a/TShockAPI/Net/DisconnectMsg.cs b/TShockAPI/Net/DisconnectMsg.cs
index ad1ebf57..a8318e6b 100644
--- a/TShockAPI/Net/DisconnectMsg.cs
+++ b/TShockAPI/Net/DisconnectMsg.cs
@@ -1,10 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
+using System.IO;
+using System.IO.Streams;
using System.Text;
-using TerrariaAPI;
-using XNAHelpers;
namespace TShockAPI.Net
{
diff --git a/TShockAPI/Net/NetTile.cs b/TShockAPI/Net/NetTile.cs
index be269a61..8871065f 100644
--- a/TShockAPI/Net/NetTile.cs
+++ b/TShockAPI/Net/NetTile.cs
@@ -19,7 +19,7 @@ along with this program. If not, see .
using System;
using System.IO;
using Terraria;
-using XNAHelpers;
+using System.IO.Streams;
namespace TShockAPI.Net
{
diff --git a/TShockAPI/Net/SpawnMsg.cs b/TShockAPI/Net/SpawnMsg.cs
index 29e9e4c9..dc851379 100644
--- a/TShockAPI/Net/SpawnMsg.cs
+++ b/TShockAPI/Net/SpawnMsg.cs
@@ -1,8 +1,5 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using TerrariaAPI;
-using XNAHelpers;
+using System.IO;
+using System.IO.Streams;
namespace TShockAPI.Net
{
diff --git a/TShockAPI/Net/WorldInfoMsg.cs b/TShockAPI/Net/WorldInfoMsg.cs
index 1ba56691..8726ced4 100644
--- a/TShockAPI/Net/WorldInfoMsg.cs
+++ b/TShockAPI/Net/WorldInfoMsg.cs
@@ -19,8 +19,8 @@ along with this program. If not, see .
using System;
using System.IO;
using System.Text;
-using TerrariaAPI;
-using XNAHelpers;
+
+using System.IO.Streams;
namespace TShockAPI.Net
{
diff --git a/TShockAPI/PacketBufferer.cs b/TShockAPI/PacketBufferer.cs
index 3b698a60..0257c78f 100644
--- a/TShockAPI/PacketBufferer.cs
+++ b/TShockAPI/PacketBufferer.cs
@@ -5,8 +5,8 @@ using System.IO;
using System.Net.Sockets;
using System.Text;
using Terraria;
-using TerrariaAPI;
-using TerrariaAPI.Hooks;
+
+using Hooks;
namespace TShockAPI
{
diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs
index 3d757948..60feba1b 100644
--- a/TShockAPI/Permissions.cs
+++ b/TShockAPI/Permissions.cs
@@ -123,6 +123,9 @@ namespace TShockAPI
[Description("User can spawn items")]
public static readonly string item;
+ [Description("User can clear item drops.")]
+ public static readonly string clearitems;
+
[Description("")]
public static readonly string heal;
diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs
index f2f36cc1..024b84db 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.0905")]
-[assembly: AssemblyFileVersion("3.3.0.0905")]
+[assembly: AssemblyVersion("3.3.4.0926")]
+[assembly: AssemblyFileVersion("3.3.4.0926")]
\ No newline at end of file
diff --git a/TShockAPI/RconHandler.cs b/TShockAPI/RconHandler.cs
index ec34f563..d407a144 100644
--- a/TShockAPI/RconHandler.cs
+++ b/TShockAPI/RconHandler.cs
@@ -24,7 +24,7 @@ using System.Net.Sockets;
using System.Text;
using System.Threading;
using Terraria;
-using XNAHelpers;
+using System.IO.Streams;
namespace TShockAPI
{
@@ -38,13 +38,30 @@ namespace TShockAPI
public static string Response = "";
private static bool Started;
private static UdpClient listener;
+ private static Thread startThread;
+ private static Thread heartbeat;
+ private static Thread listen;
+
+ public static void ShutdownAllThreads()
+ {
+ if (Started)
+ {
+ startThread.Abort();
+ heartbeat.Abort();
+ listen.Abort();
+ Started = false;
+ }
+ }
public static void StartThread()
{
if (!Started)
{
- (new Thread(Start)).Start();
- (new Thread(SendHeartbeat)).Start();
+ startThread = new Thread(Start);
+ startThread.Start();
+
+ heartbeat = new Thread(SendHeartbeat);
+ heartbeat.Start();
}
Started = true;
}
@@ -57,7 +74,7 @@ namespace TShockAPI
Console.WriteLine(string.Format("RconHandler is running at UDP port {0} and password is {1}",
ListenPort,
Password));
- Thread listen = new Thread(Listener);
+ listen = new Thread(Listener);
listen.Start();
while (true)
{
@@ -161,8 +178,8 @@ namespace TShockAPI
}
else
{
- response = "Bad rconpassword.\n";
- Log.ConsoleInfo("Bad rconpassword from " + EP);
+ response = "Bad rcon password.\n";
+ Log.ConsoleInfo("Bad rcon password from " + EP);
}
}
else
@@ -170,7 +187,7 @@ namespace TShockAPI
}
else
{
- response = "No rconpassword set on the server.\n";
+ response = "No rcon password set on the server.\n";
Log.Info("No password for rcon set");
}
}
@@ -328,7 +345,7 @@ namespace TShockAPI
{
if ((DateTime.UtcNow - LastHeartbeat).Seconds >= 30)
{
- var packet = ConstructPacket("heartbeat TERRARIA", false);
+ var packet = ConstructPacket("heartbeat TerrariaShock", false);
if (listener == null)
try
{
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..5409282f
--- /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 RequiresToken { 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;
+ RequiresToken = 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..4c11b64e
--- /dev/null
+++ b/TShockAPI/Rest/RestManager.cs
@@ -0,0 +1,448 @@
+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) { RequiresToken = false });
+ Rest.Register(new RestCommand("/tokentest", TokenTest) { RequiresToken = true });
+
+ Rest.Register(new RestCommand("/users/read/{user}/info", UserInfo) { RequiresToken = true });
+ Rest.Register(new RestCommand("/users/destroy/{user}", UserDestroy) { RequiresToken = true });
+ Rest.Register(new RestCommand("/users/update/{user}", UserUpdate) { RequiresToken = true });
+
+ Rest.Register(new RestCommand("/bans/create", BanCreate) { RequiresToken = true });
+ Rest.Register(new RestCommand("/bans/read/{user}/info", BanInfo) { RequiresToken = true });
+ Rest.Register(new RestCommand("/bans/destroy/{user}", BanDestroy) { RequiresToken = true });
+
+
+ Rest.Register(new RestCommand("/lists/players", UserList) { RequiresToken = true });
+
+ Rest.Register(new RestCommand("/world/read", WorldRead) { RequiresToken = true });
+ Rest.Register(new RestCommand("/world/meteor", WorldMeteor) { RequiresToken = true });
+ Rest.Register(new RestCommand("/world/bloodmoon/{bool}", WorldBloodmoon) { RequiresToken = true });
+
+ Rest.Register(new RestCommand("/players/read/{player}", PlayerRead) { RequiresToken = true });
+ Rest.Register(new RestCommand("/players/{player}/kick", PlayerKick) { RequiresToken = true });
+ Rest.Register(new RestCommand("/players/{player}/ban", PlayerBan) { RequiresToken = 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);
+ returnBlock.Add("daytime", Main.dayTime);
+ returnBlock.Add("bloodmoon", Main.bloodMoon);
+ returnBlock.Add("invasionsize", Main.invasionSize);
+ 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 RestPlayerMethods
+ object PlayerRead(RestVerbs verbs, IParameterCollection parameters)
+ {
+ var returnBlock = new Dictionary();
+ var playerParam = parameters["player"];
+ var found = Tools.FindPlayer(playerParam.ToString());
+ if (found.Count == 0)
+ {
+ returnBlock.Add("status", "400");
+ returnBlock.Add("error", "Name " + playerParam.ToString() + " was not found");
+ }
+ else if (found.Count > 1)
+ {
+ returnBlock.Add("status", "400");
+ returnBlock.Add("error", "Name " + playerParam.ToString() + " matches " + playerParam.Count().ToString() + " players");
+ }
+ else if (found.Count == 1)
+ {
+ var player = found[0];
+ returnBlock.Add("status", "200");
+ returnBlock.Add("nickname", player.Name);
+ returnBlock.Add("username", player.UserAccountName == null ? "" : player.UserAccountName);
+ returnBlock.Add("ip", player.IP);
+ returnBlock.Add("group", player.Group.Name);
+ returnBlock.Add("position", player.TileX.ToString() + "," + player.TileY.ToString());
+ var activeItems = player.TPlayer.inventory.Where(p => p.active).ToList();
+ returnBlock.Add("inventory", string.Join(", ", activeItems.Select(p => p.name)));
+ returnBlock.Add("buffs", string.Join(", ", player.TPlayer.buffType));
+ }
+ return returnBlock;
+ }
+ object PlayerKick(RestVerbs verbs, IParameterCollection parameters)
+ {
+ var returnBlock = new Dictionary();
+ var playerParam = parameters["player"];
+ var found = Tools.FindPlayer(playerParam.ToString());
+ var reason = verbs["reason"];
+ if (found.Count == 0)
+ {
+ returnBlock.Add("status", "400");
+ returnBlock.Add("error", "Name " + playerParam.ToString() + " was not found");
+ }
+ else if (found.Count > 1)
+ {
+ returnBlock.Add("status", "400");
+ returnBlock.Add("error", "Name " + playerParam.ToString() + " matches " + playerParam.Count().ToString() + " players");
+ }
+ else if (found.Count == 1)
+ {
+ var player = found[0];
+ Tools.ForceKick(player, reason == null ? "Kicked via web" : reason.ToString());
+ returnBlock.Add("status", "200");
+ returnBlock.Add("response", "Player " + player.Name + " was kicked");
+ }
+ return returnBlock;
+ }
+ object PlayerBan(RestVerbs verbs, IParameterCollection parameters)
+ {
+ var returnBlock = new Dictionary();
+ var playerParam = parameters["player"];
+ var found = Tools.FindPlayer(playerParam.ToString());
+ var reason = verbs["reason"];
+ if (found.Count == 0)
+ {
+ returnBlock.Add("status", "400");
+ returnBlock.Add("error", "Name " + playerParam.ToString() + " was not found");
+ }
+ else if (found.Count > 1)
+ {
+ returnBlock.Add("status", "400");
+ returnBlock.Add("error", "Name " + playerParam.ToString() + " matches " + playerParam.Count().ToString() + " players");
+ }
+ else if (found.Count == 1)
+ {
+ var player = found[0];
+ TShock.Bans.AddBan(player.IP, player.Name, reason == null ? "Banned via web" : reason.ToString());
+ Tools.ForceKick(player, reason == null ? "Banned via web" : reason.ToString());
+ returnBlock.Add("status", "200");
+ returnBlock.Add("response", "Player " + player.Name + " was banned");
+ }
+ return returnBlock;
+ }
+ #endregion
+
+ #region RestExampleMethods
+
+ public void RegisterExamples()
+ {
+ Rest.Register(new RestCommand("/HelloWorld/name/{username}", UserTest) { RequiresToken = false });
+ Rest.Register(new RestCommand("/wizard/{username}", Wizard) { RequiresToken = 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..eb0631d9
--- /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"] as string; }
+ set { this["status"] = value; }
+ }
+ public string Error
+ {
+ get { return this["error"] as string; }
+ set { this["error"] = value; }
+ }
+ public string Response
+ {
+ get { return this["response"] as string; }
+ 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 object this[string key]
+ {
+ get
+ {
+ object 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..db12f1fe
--- /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) { RequiresToken = false });
+ Register(new RestCommand("/token/destroy/{token}", DestroyToken) { RequiresToken = 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.RequiresToken)
+ {
+ 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/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index 30abe815..9afef6e8 100644
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -17,13 +17,12 @@ along with this program. If not, see .
*/
using System;
using System.Collections.Generic;
-using System.Drawing;
+
using System.IO;
using System.Threading;
using Terraria;
-using TerrariaAPI;
+
using TShockAPI.Net;
-using XNAHelpers;
namespace TShockAPI
{
@@ -32,7 +31,7 @@ namespace TShockAPI
public static readonly TSServerPlayer Server = new TSServerPlayer();
public static readonly TSPlayer All = new TSPlayer("All");
public int TileThreshold { get; set; }
- public Dictionary TilesDestroyed { get; protected set; }
+ public Dictionary TilesDestroyed { get; protected set; }
public bool SyncHP { get; set; }
public bool SyncMP { get; set; }
public Group Group { get; set; }
@@ -46,10 +45,10 @@ namespace TShockAPI
public DateTime LastTileChangeNotify { get; set; }
public bool InitSpawn;
public bool DisplayLogs = true;
- public PointF oldSpawn = PointF.Empty;
+ public Vector2 oldSpawn = Vector2.Zero;
public TSPlayer LastWhisper;
public int LoginAttempts { get; set; }
- public PointF TeleportCoords = new PointF(-1, -1);
+ public Vector2 TeleportCoords = new Vector2(-1, -1);
public string UserAccountName { get; set; }
public bool HasBeenSpammedWithBuildMessage;
public bool IsLoggedIn;
@@ -69,7 +68,7 @@ namespace TShockAPI
}
public bool ConnectionAlive
{
- get { return RealPlayer ? Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill : false; }
+ get { return RealPlayer && (Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill); }
}
public string IP
{
@@ -145,14 +144,14 @@ namespace TShockAPI
public TSPlayer(int index)
{
- TilesDestroyed = new Dictionary();
+ TilesDestroyed = new Dictionary();
Index = index;
Group = new Group("null");
}
protected TSPlayer(String playerName)
{
- TilesDestroyed = new Dictionary();
+ TilesDestroyed = new Dictionary();
Index = -1;
FakePlayer = new Player { name = playerName, whoAmi = -1 };
Group = new Group("null");
@@ -213,7 +212,7 @@ namespace TShockAPI
//150 Should avoid all client crash errors
//The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks
//Try 300 if it does not work (Higher number - Longer load times - Less chance of error)
- if (!SendTileSquare(tilex, tiley, 150))
+ if (!SendTileSquare(tilex, tiley))
{
InitSpawn = true;
SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false);
@@ -225,6 +224,9 @@ namespace TShockAPI
SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false);
+ TPlayer.position.X = tilex;
+ TPlayer.position.Y = tiley;
+
return true;
}
@@ -406,17 +408,17 @@ namespace TShockAPI
NetMessage.SendData((int)PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection);
}
- public void RevertKillTile(Dictionary destroyedTiles)
+ public void RevertKillTile(Dictionary destroyedTiles)
{
// Update Main.Tile first so that when tile sqaure is sent it is correct
- foreach (KeyValuePair entry in destroyedTiles)
+ foreach (KeyValuePair entry in destroyedTiles)
{
- Main.tile[(int)entry.Key.X, (int)entry.Key.Y] = entry.Value;
+ Main.tile[(int)entry.Key.X, (int)entry.Key.Y].Data = entry.Value;
Log.Debug(string.Format("Reverted DestroyedTile(TileXY:{0}_{1}, Type:{2})",
entry.Key.X, entry.Key.Y, Main.tile[(int)entry.Key.X, (int)entry.Key.Y].type));
}
// Send all players updated tile sqaures
- foreach (PointF coords in destroyedTiles.Keys)
+ foreach (Vector2 coords in destroyedTiles.Keys)
{
All.SendTileSquare((int)coords.X, (int)coords.Y, 3);
}
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index 1b06aaef..be8a4eb4 100644
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -29,17 +29,15 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
-using System.Drawing;
using System.IO;
using System.Net;
using System.Reflection;
-using System.Linq;
using System.Threading;
using Community.CsharpSqlite.SQLiteClient;
+using Hooks;
using MySql.Data.MySqlClient;
+using Rests;
using Terraria;
-using TerrariaAPI;
-using TerrariaAPI.Hooks;
using TShockAPI.DB;
using TShockAPI.Net;
@@ -49,7 +47,7 @@ namespace TShockAPI
public class TShock : TerrariaPlugin
{
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
- public static readonly string VersionCodename = "And believe me, we are still alive.";
+ public static readonly string VersionCodename = "Try the new slim model.";
public static string SavePath = "tshock";
@@ -67,6 +65,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.
@@ -142,7 +142,7 @@ namespace TShockAPI
var hostport = Config.MySqlHost.Split(':');
DB = new MySqlConnection();
DB.ConnectionString =
- String.Format("Server='{0}'; Port='{1}'; Database='{2}'; Uid='{3}'; Pwd='{4}';",
+ String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};",
hostport[0],
hostport.Length > 1 ? hostport[1] : "3306",
Config.MySqlDbName,
@@ -172,8 +172,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(Netplay.serverListenIP, 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,23 +216,50 @@ namespace TShockAPI
}
}
- public override void DeInitialize()
+ RestObject RestApi_Verify(string username, string password)
{
- GameHooks.PostInitialize -= OnPostInit;
- GameHooks.Update -= OnUpdate;
- ServerHooks.Join -= OnJoin;
- ServerHooks.Leave -= OnLeave;
- ServerHooks.Chat -= OnChat;
- ServerHooks.Command -= ServerHooks_OnCommand;
- NetHooks.GetData -= OnGetData;
- NetHooks.SendData -= NetHooks_SendData;
- NetHooks.GreetPlayer -= OnGreetPlayer;
- NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc;
- if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
+ var userAccount = TShock.Users.GetUserByName(username);
+ if (userAccount == null)
{
- Console.WriteLine("Thanks for using TShock! Process ID file is now being destroyed.");
- File.Delete(Path.Combine(SavePath, "tshock.pid"));
+ 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?
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ GameHooks.PostInitialize -= OnPostInit;
+ GameHooks.Update -= OnUpdate;
+ ServerHooks.Join -= OnJoin;
+ ServerHooks.Leave -= OnLeave;
+ ServerHooks.Chat -= OnChat;
+ ServerHooks.Command -= ServerHooks_OnCommand;
+ NetHooks.GetData -= OnGetData;
+ NetHooks.SendData -= NetHooks_SendData;
+ NetHooks.GreetPlayer -= OnGreetPlayer;
+ NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc;
+ if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
+ {
+ Console.WriteLine("Thanks for using TShock! Process ID file is now being destroyed.");
+ File.Delete(Path.Combine(SavePath, "tshock.pid"));
+ }
+ RestApi.Dispose();
+ }
+
+ base.Dispose(disposing);
}
///
@@ -352,6 +386,8 @@ namespace TShockAPI
AuthToken = 0;
}
Regions.ReloadAllRegions();
+ if (Config.RestApiEnabled)
+ RestApi.Start();
}
@@ -624,7 +660,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);
@@ -813,11 +849,11 @@ namespace TShockAPI
public static bool CheckSpawn(int x, int y)
{
- PointF tile = new PointF(x, y);
- PointF spawn = new PointF(Main.spawnTileX, Main.spawnTileY);
+ Vector2 tile = new Vector2(x, y);
+ Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY);
return Distance(spawn, tile) <= Config.SpawnProtectionRadius;
}
- public static float Distance(PointF value1, PointF value2)
+ public static float Distance(Vector2 value1, Vector2 value2)
{
float num2 = value1.X - value2.X;
float num = value1.Y - value2.Y;
diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj
index 523752e5..cfebb727 100644
--- a/TShockAPI/TShockAPI.csproj
+++ b/TShockAPI/TShockAPI.csproj
@@ -32,7 +32,7 @@
true
full
false
- ..\..\serverplugins\
+ ..\..\..\Downloads\TShock 3.3.4.924\ServerPlugins\
DEBUG;TRACE
prompt
4
@@ -52,6 +52,9 @@
False
..\SqlBins\Community.CsharpSqlite.SQLiteClient.dll
+
+ ..\HttpBins\HttpServer.dll
+
False
..\SqlBins\MySql.Data.dll
@@ -67,7 +70,6 @@
-
@@ -79,10 +81,6 @@
..\TerrariaServerBins\TerrariaServer.exe
False
-
- False
- ..\TerrariaServerBins\TerrariaServerAPI.dll
-
@@ -121,6 +119,12 @@
True
Resources.resx
+
+
+
+
+
+
@@ -177,7 +181,7 @@
-
+