public AspNetContext(HttpContext httpContext) { // Assign properties _request = new AspNetRequest(httpContext.Request); _session = new AspNetSession(httpContext); _response = new AspNetResponse(httpContext.Response); }
public AspNetContext(HttpContext httpContext, string resourcePath = null) { // Assign properties _request = new AspNetRequest(httpContext.Request); _request.ResourcePath = new Uri(resourcePath, UriKind.RelativeOrAbsolute); _session = new AspNetSession(httpContext); _response = new AspNetResponse(httpContext.Response); }
private AspNetResponse FollowAnyRedirect(AspNetResponse response) { if (response.Status == 302 || response.Status == 301) { var location = response.Headers.First(x => x.Key == "Location").Value; var locationUri = new Uri(location, UriKind.RelativeOrAbsolute); var url = locationUri.IsAbsoluteUri ? locationUri.PathAndQuery : location; var request = new AspNetRequest(url, null, null, "GET", CreateRequestHeaders(new WebHeaderCollection()), null); return(ProcessRequest(request)); } return(response); }
private void ExtractCookies(AspNetResponse response) { if (cookieContainer == null) { return; } foreach (var cookie in response.CookieHeader) { cookieContainer.SetCookies(new Uri("http://localhost"), cookie); } }
public HttpPlasmaResponse(AspNetResponse response) { this.response = response; }
public void Handle(AspNetRequest request, AspNetResponse response) { var handleScope = IronRubyEngine.Engine.CreateScope(); //handle_scope.SetVariable("__request", request); handleScope.SetVariable("__response", response); // The environment must be an true instance of Hash (no subclassing // allowed) that includes CGI-like headers. The application is free // to modify the environment. The environment is required to // include these variables (adopted from PEP333), except when // they’d be empty, but see below. var env = new Hash(IronRubyEngine.Context); // REQUEST_METHOD: The HTTP request method, such as “GET” or // “POST”. This cannot ever be an empty string, and so is always // required. // The REQUEST_METHOD must be a valid token. SetEnv(env, "REQUEST_METHOD", request.OrigionalRequest.RequestType); // SCRIPT_NAME: The initial portion of the request URL’s “path” // that corresponds to the application object, so that the // application knows its virtual “location”. This may be an empty // string, if the application corresponds to the “root” of the // server. // The SCRIPT_NAME, if non-empty, must start with / string scriptName = request.OrigionalRequest.ApplicationPath; if (scriptName.Length > 0 && !scriptName.StartsWith("/")) { scriptName = "/" + scriptName; } // SCRIPT_NAME never should be /, but instead be empty. if (scriptName == "/") { scriptName = string.Empty; } SetEnv(env, "SCRIPT_NAME", scriptName); // PATH_INFO: The remainder of the request URL’s “path”, // designating the virtual “location” of the request’s target // within the application. This may be an empty string, if the // request URL targets the application root and does not have a // trailing slash. This value may be percent-encoded when I // originating from a URL. // The PATH_INFO, if non-empty, must start with / string pathInfo = request.OrigionalRequest.Path.Substring( request.OrigionalRequest.Path.IndexOf(request.OrigionalRequest.ApplicationPath) + request.OrigionalRequest.ApplicationPath.Length ); if (pathInfo.Length > 0 && !pathInfo.StartsWith("/")) { pathInfo = "/" + pathInfo; } // PATH_INFO should be / if SCRIPT_NAME is empty. if (pathInfo.Length == 0) { pathInfo = "/"; } SetEnv(env, "PATH_INFO", pathInfo); // One of SCRIPT_NAME or PATH_INFO must be set. // TODO // QUERY_STRING: The portion of the request URL that follows the // ?, if any. May be empty, but is always required! SetEnv(env, "QUERY_STRING", request.QueryString ?? ""); // SERVER_NAME, SERVER_PORT: When combined with SCRIPT_NAME and // PATH_INFO, these variables can be used to complete the URL. // Note, however, that HTTP_HOST, if present, should be used in // preference to SERVER_NAME for reconstructing the request URL. // SERVER_NAME and SERVER_PORT can never be empty strings, and so // are always required. SetEnv(env, "SERVER_NAME", request.OrigionalRequest.Url.Host); SetEnv(env, "SERVER_PORT", request.OrigionalRequest.Url.Port.ToString()); // HTTP_ Variables: Variables corresponding to the client-supplied // HTTP request headers (i.e., variables whose names begin with // HTTP_). The presence or absence of these variables should // correspond with the presence or absence of the appropriate // HTTP header in the request. // The CONTENT_LENGTH, if given, must consist of digits only. foreach (var pair in request.Headers) { var prepend = "HTTP_"; if (pair.Key.ToString() == "Content-Length" || pair.Key.ToString() == "Content-Type") { prepend = ""; } SetEnv(env, prepend + pair.Key.ToString().ToUpper().Replace("-", "_"), pair.Value.ToString()); } // In addition to this, the Rack environment must include these // Rack-specific variables: // // rack.version: The Array (for example: [1, 0], representing // this version of Rack. SetEnv(env, "rack.version", App.ActualRackVersion); // rack.url_scheme: http or https, depending on the request URL. SetEnv(env, "rack.url_scheme", request.OrigionalRequest.IsSecureConnection ? "https" : "http"); // rack.input: The input stream is an IO-like object which contains // the raw HTTP POST data. If it is a file then it must be opened // in binary mode. The input stream must respond to gets, each, // read and rewind. // // gets must be called without arguments and return a string, or // nil on EOF. // read behaves like IO#read. Its signature is // read([length, [buffer]]). If given, length must be an // non-negative Integer (>= 0) or nil, and buffer must be a String // and may not be nil. If length is given and not nil, then this // method reads at most length bytes from the input stream. If // length is not given or nil, then this method reads all data // until EOF. When EOF is reached, this method returns nil if // length is given and not nil, or “” if length is not given or // is nil. If buffer is given, then the read data will be placed // into buffer instead of a newly created String object. // each must be called without arguments and only yield Strings. // rewind must be called without arguments. It rewinds the input // stream back to the beginning. It must not raise Errno::ESPIPE: // that is, it may not be a pipe or a socket. Therefore, handler // developers must buffer the input data into some rewindable // object if the underlying input stream is not rewindable. // close must never be called on the input stream. SetEnv(env, "rack.input", request.Body); // rack.errors: The error stream must respond to puts, write and flush. // // puts must be called with a single argument that responds to to_s. // write must be called with a single argument that is a String. // flush must be called without arguments and must be called in // order to make the error appear for sure. // close must never be called on the error stream. SetEnv(env, "rack.errors", IronRubyEngine.Context.StandardErrorOutput); // rack.multithread: true if the application object may be simultaneously // invoked by another thread in the same process, false otherwise. SetEnv(env, "rack.multithread", true); // rack.multiprocess: true if an equivalent application object may be // simultaneously invoked by another process, false otherwise. SetEnv(env, "rack.multiprocess", false); // rack.run_once: true if the server expects (but does not guarantee!) // that the application will only be invoked this one time during the // life of its containing process. Normally, this will only be true for // a server based on CGI (or something similar). SetEnv(env, "rack.run_once", false); // Additional environment specifications have approved to standardized // middleware APIs. None of these are required to be implemented by the server. // // rack.session: A hash like interface for storing request session data. // The store must implement: // store(key, value) (aliased as []=); // fetch(key, default = nil) (aliased as []); // delete(key); // clear; // noop // The server or the application can store their own data in the // environment, too. The keys must contain at least one dot, and // should be prefixed uniquely. The prefix rack. is reserved for // use with the Rack core distribution and other accepted // specifications and must not be used otherwise. // noop // The environment // must not contain the keys HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH // (use the versions without HTTP_). The CGI keys (named without a period) // must have String values. RemoveEnv(env, "HTTP_CONTENT_LENGTH"); RemoveEnv(env, "HTTP_CONTENT_TYPE"); // Set other vars based on what WEBrick sets: SetEnv(env, "REMOTE_HOST", request.OrigionalRequest.Url.Host); SetEnv(env, "SERVER_PROTOCOL", request.OrigionalRequest.Params["SERVER_PROTOCOL"]); SetEnv(env, "REQUEST_PATH", request.OrigionalRequest.Path); SetEnv(env, "SERVER_SOFTWARE", request.OrigionalRequest.Params["SERVER_SOFTWARE"]); SetEnv(env, "REMOTE_ADDR", request.OrigionalRequest.Url.AbsoluteUri); SetEnv(env, "HTTP_VERSION", request.OrigionalRequest.Params["SERVER_PROTOCOL"]); SetEnv(env, "REQUEST_URI", request.OrigionalRequest.Url.AbsoluteUri); SetEnv(env, "GATEWAY_INTERFACE", request.OrigionalRequest.Params["GATEWAY_INTERFACE"]); // A Rack application is an Ruby object (not a class) that responds // to call. It takes exactly one argument, the environment and // returns an Array of exactly three values: The status, the headers, // and the body. RubyArray ruby_response = App.Call(env); try { // The Response // ============ // The Status // ---------- // This is an HTTP status. When parsed as integer (to_i), it // must be greater than or equal to 100. response.Status = (int)ruby_response[0]; // The Headers // ----------- // The header must respond to each, and yield values of key and // value. The header keys must be Strings. The header must not // contain a Status key, contain keys with : or newlines in // their name, contain keys names that end in - or _, but only // contain keys that consist of letters, digits, _ or - and // start with a letter. The values of the header must be // Strings, consisting of lines (for multiple header values, // e.g. multiple Set-Cookie values) seperated by “n“. The lines // must not contain characters below 037. foreach (var header in ((Hash)ruby_response[1])) { foreach (var value in header.Value.ToString().Split('\n')) { response.AppendHeader(header.Key.ToString(), value.ToString()); } } // The Content-Type // ---------------- // There must be a Content-Type, except when the Status is 1xx, // 204 or 304, in which case there must be none given. // TODO // The Content-Length // ------------------ // There must not be a Content-Length header when the Status is // 1xx, 204 or 304. // TODO // The Body // -------- // The Body must respond to each and must only yield String // values. The Body itself should not be an instance of String, // as this will break in Ruby 1.9. If the Body responds to // close, it will be called after iteration. If the Body // responds to to_path, it must return a String identifying the // location of a file whose contents are identical to that // produced by calling each; this may be used by the server as // an alternative, possibly more efficient way to transport the // response. The Body commonly is an Array of Strings, the // application instance itself, or a File-like object. var body = ruby_response[2]; var each_block = (Func <IronRuby.Runtime.BlockParam, object, object, object>)((block, notUsed, part) => { response.Write(((MutableString)part).ToByteArray()); return(null); }); handleScope.SetVariable("__body", ruby_response[2]); handleScope.SetVariable("__each_block", Proc.CreateSimple(IronRubyEngine.Context, each_block)); IronRubyEngine.Execute("__body.each(&__each_block)", handleScope); } finally { var body = ruby_response[2]; if (IronRubyEngine.ExecuteMethod <bool>(body, "respond_to?", "close")) { IronRubyEngine.ExecuteMethod(body, "close"); } } }
public void Handle(AspNetRequest request, AspNetResponse response) { var handleScope = IronRubyEngine.Engine.CreateScope(); //handle_scope.SetVariable("__request", request); handleScope.SetVariable("__response", response); // The environment must be an true instance of Hash (no subclassing // allowed) that includes CGI-like headers. The application is free // to modify the environment. The environment is required to // include these variables (adopted from PEP333), except when // they’d be empty, but see below. var env = new Hash(IronRubyEngine.Context); // REQUEST_METHOD: The HTTP request method, such as “GET” or // “POST”. This cannot ever be an empty string, and so is always // required. // The REQUEST_METHOD must be a valid token. SetEnv(env, "REQUEST_METHOD", request.OrigionalRequest.RequestType); // SCRIPT_NAME: The initial portion of the request URL’s “path” // that corresponds to the application object, so that the // application knows its virtual “location”. This may be an empty // string, if the application corresponds to the “root” of the // server. // The SCRIPT_NAME, if non-empty, must start with / string scriptName = request.OrigionalRequest.ApplicationPath; if(scriptName.Length > 0 && !scriptName.StartsWith("/")) { scriptName = "/" + scriptName; } // SCRIPT_NAME never should be /, but instead be empty. if (scriptName == "/") scriptName = string.Empty; SetEnv(env, "SCRIPT_NAME", scriptName); // PATH_INFO: The remainder of the request URL’s “path”, // designating the virtual “location” of the request’s target // within the application. This may be an empty string, if the // request URL targets the application root and does not have a // trailing slash. This value may be percent-encoded when I // originating from a URL. // The PATH_INFO, if non-empty, must start with / string pathInfo = request.OrigionalRequest.Path.Substring( request.OrigionalRequest.Path.IndexOf(request.OrigionalRequest.ApplicationPath) + request.OrigionalRequest.ApplicationPath.Length ); if(pathInfo.Length > 0 && !pathInfo.StartsWith("/")) { pathInfo = "/" + pathInfo; } // PATH_INFO should be / if SCRIPT_NAME is empty. if(pathInfo.Length == 0) pathInfo = "/"; SetEnv(env, "PATH_INFO", pathInfo); // One of SCRIPT_NAME or PATH_INFO must be set. // TODO // QUERY_STRING: The portion of the request URL that follows the // ?, if any. May be empty, but is always required! SetEnv(env, "QUERY_STRING", request.QueryString ?? ""); // SERVER_NAME, SERVER_PORT: When combined with SCRIPT_NAME and // PATH_INFO, these variables can be used to complete the URL. // Note, however, that HTTP_HOST, if present, should be used in // preference to SERVER_NAME for reconstructing the request URL. // SERVER_NAME and SERVER_PORT can never be empty strings, and so // are always required. SetEnv(env, "SERVER_NAME", request.OrigionalRequest.Url.Host); SetEnv(env, "SERVER_PORT", request.OrigionalRequest.Url.Port.ToString()); // HTTP_ Variables: Variables corresponding to the client-supplied // HTTP request headers (i.e., variables whose names begin with // HTTP_). The presence or absence of these variables should // correspond with the presence or absence of the appropriate // HTTP header in the request. // The CONTENT_LENGTH, if given, must consist of digits only. foreach (var pair in request.Headers) { var prepend = "HTTP_"; if (pair.Key.ToString() == "Content-Length" || pair.Key.ToString() == "Content-Type") prepend = ""; SetEnv(env, prepend + pair.Key.ToString().ToUpper().Replace("-", "_"), pair.Value.ToString()); } // In addition to this, the Rack environment must include these // Rack-specific variables: // // rack.version: The Array (for example: [1, 0], representing // this version of Rack. SetEnv(env, "rack.version", App.ActualRackVersion); // rack.url_scheme: http or https, depending on the request URL. SetEnv(env, "rack.url_scheme", request.OrigionalRequest.IsSecureConnection ? "https" : "http"); // rack.input: The input stream is an IO-like object which contains // the raw HTTP POST data. If it is a file then it must be opened // in binary mode. The input stream must respond to gets, each, // read and rewind. // // gets must be called without arguments and return a string, or // nil on EOF. // read behaves like IO#read. Its signature is // read([length, [buffer]]). If given, length must be an // non-negative Integer (>= 0) or nil, and buffer must be a String // and may not be nil. If length is given and not nil, then this // method reads at most length bytes from the input stream. If // length is not given or nil, then this method reads all data // until EOF. When EOF is reached, this method returns nil if // length is given and not nil, or “” if length is not given or // is nil. If buffer is given, then the read data will be placed // into buffer instead of a newly created String object. // each must be called without arguments and only yield Strings. // rewind must be called without arguments. It rewinds the input // stream back to the beginning. It must not raise Errno::ESPIPE: // that is, it may not be a pipe or a socket. Therefore, handler // developers must buffer the input data into some rewindable // object if the underlying input stream is not rewindable. // close must never be called on the input stream. SetEnv(env, "rack.input", request.Body); // rack.errors: The error stream must respond to puts, write and flush. // // puts must be called with a single argument that responds to to_s. // write must be called with a single argument that is a String. // flush must be called without arguments and must be called in // order to make the error appear for sure. // close must never be called on the error stream. SetEnv(env, "rack.errors", IronRubyEngine.Context.StandardErrorOutput); // rack.multithread: true if the application object may be simultaneously // invoked by another thread in the same process, false otherwise. SetEnv(env, "rack.multithread", true); // rack.multiprocess: true if an equivalent application object may be // simultaneously invoked by another process, false otherwise. SetEnv(env, "rack.multiprocess", false); // rack.run_once: true if the server expects (but does not guarantee!) // that the application will only be invoked this one time during the // life of its containing process. Normally, this will only be true for // a server based on CGI (or something similar). SetEnv(env, "rack.run_once", false); // Additional environment specifications have approved to standardized // middleware APIs. None of these are required to be implemented by the server. // // rack.session: A hash like interface for storing request session data. // The store must implement: // store(key, value) (aliased as []=); // fetch(key, default = nil) (aliased as []); // delete(key); // clear; // noop // The server or the application can store their own data in the // environment, too. The keys must contain at least one dot, and // should be prefixed uniquely. The prefix rack. is reserved for // use with the Rack core distribution and other accepted // specifications and must not be used otherwise. // noop // The environment // must not contain the keys HTTP_CONTENT_TYPE or HTTP_CONTENT_LENGTH // (use the versions without HTTP_). The CGI keys (named without a period) // must have String values. RemoveEnv(env, "HTTP_CONTENT_LENGTH"); RemoveEnv(env, "HTTP_CONTENT_TYPE"); // Set other vars based on what WEBrick sets: SetEnv(env, "REMOTE_HOST", request.OrigionalRequest.Url.Host); SetEnv(env, "SERVER_PROTOCOL", request.OrigionalRequest.Params["SERVER_PROTOCOL"]); SetEnv(env, "REQUEST_PATH", request.OrigionalRequest.Path); SetEnv(env, "SERVER_SOFTWARE", request.OrigionalRequest.Params["SERVER_SOFTWARE"]); SetEnv(env, "REMOTE_ADDR", request.OrigionalRequest.Url.AbsoluteUri); SetEnv(env, "HTTP_VERSION", request.OrigionalRequest.Params["SERVER_PROTOCOL"]); SetEnv(env, "REQUEST_URI", request.OrigionalRequest.Url.AbsoluteUri); SetEnv(env, "GATEWAY_INTERFACE", request.OrigionalRequest.Params["GATEWAY_INTERFACE"]); // A Rack application is an Ruby object (not a class) that responds // to call. It takes exactly one argument, the environment and // returns an Array of exactly three values: The status, the headers, // and the body. RubyArray ruby_response = App.Call(env); try { // The Response // ============ // The Status // ---------- // This is an HTTP status. When parsed as integer (to_i), it // must be greater than or equal to 100. response.Status = (int)ruby_response[0]; // The Headers // ----------- // The header must respond to each, and yield values of key and // value. The header keys must be Strings. The header must not // contain a Status key, contain keys with : or newlines in // their name, contain keys names that end in - or _, but only // contain keys that consist of letters, digits, _ or - and // start with a letter. The values of the header must be // Strings, consisting of lines (for multiple header values, // e.g. multiple Set-Cookie values) seperated by “n“. The lines // must not contain characters below 037. foreach (var header in ((Hash)ruby_response[1])) { foreach (var value in header.Value.ToString().Split('\n')) { response.AppendHeader(header.Key.ToString(), value.ToString()); } } // The Content-Type // ---------------- // There must be a Content-Type, except when the Status is 1xx, // 204 or 304, in which case there must be none given. // TODO // The Content-Length // ------------------ // There must not be a Content-Length header when the Status is // 1xx, 204 or 304. // TODO // The Body // -------- // The Body must respond to each and must only yield String // values. The Body itself should not be an instance of String, // as this will break in Ruby 1.9. If the Body responds to // close, it will be called after iteration. If the Body // responds to to_path, it must return a String identifying the // location of a file whose contents are identical to that // produced by calling each; this may be used by the server as // an alternative, possibly more efficient way to transport the // response. The Body commonly is an Array of Strings, the // application instance itself, or a File-like object. var body = ruby_response[2]; var each_block = (Func<IronRuby.Runtime.BlockParam, object, object, object>)((block, notUsed, part) => { response.Write(((MutableString)part).ToByteArray()); return null; }); handleScope.SetVariable("__body", ruby_response[2]); handleScope.SetVariable("__each_block", Proc.CreateSimple(IronRubyEngine.Context, each_block)); IronRubyEngine.Execute("__body.each(&__each_block)", handleScope); } finally { var body = ruby_response[2]; if (IronRubyEngine.ExecuteMethod<bool>(body, "respond_to?", "close")) { IronRubyEngine.ExecuteMethod(body, "close"); } } }