├── .gitignore ├── .travis.yml ├── HttpSimulator.Tests ├── HttpSimulator.Tests.csproj ├── Test.cs └── packages.config ├── HttpSimulator.sln ├── HttpSimulator ├── BaseWrapped │ ├── HttpContext.cs │ ├── HttpServerUtility.cs │ ├── HttpSessionState.cs │ └── SimulatedHttpRequest.cs ├── HttpSimulator.cs ├── HttpSimulator.csproj ├── IHttpContext.cs ├── IHttpRequest.cs ├── IHttpResponse.cs ├── IHttpServerUtility.cs ├── Properties │ └── AssemblyInfo.cs ├── ReflectionHelper.cs └── SimulatedHttpRequest.cs ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/monodevelop,visualstudio,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=monodevelop,visualstudio,visualstudiocode 4 | 5 | ### MonoDevelop ### 6 | #User Specific 7 | *.userprefs 8 | *.usertasks 9 | 10 | #Mono Project Files 11 | *.pidb 12 | *.resources 13 | test-results/ 14 | 15 | ### VisualStudioCode ### 16 | .vscode/* 17 | !.vscode/settings.json 18 | !.vscode/tasks.json 19 | !.vscode/launch.json 20 | !.vscode/extensions.json 21 | 22 | ### VisualStudioCode Patch ### 23 | # Ignore all local history of files 24 | .history 25 | 26 | ### VisualStudio ### 27 | ## Ignore Visual Studio temporary files, build results, and 28 | ## files generated by popular Visual Studio add-ons. 29 | ## 30 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 31 | 32 | # User-specific files 33 | *.rsuser 34 | *.suo 35 | *.user 36 | *.userosscache 37 | *.sln.docstates 38 | 39 | # User-specific files (MonoDevelop/Xamarin Studio) 40 | 41 | # Mono auto generated files 42 | mono_crash.* 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Dd]ebugPublic/ 47 | [Rr]elease/ 48 | [Rr]eleases/ 49 | x64/ 50 | x86/ 51 | [Aa][Rr][Mm]/ 52 | [Aa][Rr][Mm]64/ 53 | bld/ 54 | [Bb]in/ 55 | [Oo]bj/ 56 | [Ll]og/ 57 | 58 | # Visual Studio 2015/2017 cache/options directory 59 | .vs/ 60 | # Uncomment if you have tasks that create the project's static files in wwwroot 61 | #wwwroot/ 62 | 63 | # Visual Studio 2017 auto generated files 64 | Generated\ Files/ 65 | 66 | # MSTest test Results 67 | [Tt]est[Rr]esult*/ 68 | [Bb]uild[Ll]og.* 69 | 70 | # NUnit 71 | *.VisualState.xml 72 | TestResult.xml 73 | nunit-*.xml 74 | 75 | # Build Results of an ATL Project 76 | [Dd]ebugPS/ 77 | [Rr]eleasePS/ 78 | dlldata.c 79 | 80 | # Benchmark Results 81 | BenchmarkDotNet.Artifacts/ 82 | 83 | # .NET Core 84 | project.lock.json 85 | project.fragment.lock.json 86 | artifacts/ 87 | 88 | # StyleCop 89 | StyleCopReport.xml 90 | 91 | # Files built by Visual Studio 92 | *_i.c 93 | *_p.c 94 | *_h.h 95 | *.ilk 96 | *.obj 97 | *.iobj 98 | *.pch 99 | *.pdb 100 | *.ipdb 101 | *.pgc 102 | *.pgd 103 | *.rsp 104 | *.sbr 105 | *.tlb 106 | *.tli 107 | *.tlh 108 | *.tmp 109 | *.tmp_proj 110 | *_wpftmp.csproj 111 | *.log 112 | *.vspscc 113 | *.vssscc 114 | .builds 115 | *.svclog 116 | *.scc 117 | 118 | # Chutzpah Test files 119 | _Chutzpah* 120 | 121 | # Visual C++ cache files 122 | ipch/ 123 | *.aps 124 | *.ncb 125 | *.opendb 126 | *.opensdf 127 | *.sdf 128 | *.cachefile 129 | *.VC.db 130 | *.VC.VC.opendb 131 | 132 | # Visual Studio profiler 133 | *.psess 134 | *.vsp 135 | *.vspx 136 | *.sap 137 | 138 | # Visual Studio Trace Files 139 | *.e2e 140 | 141 | # TFS 2012 Local Workspace 142 | $tf/ 143 | 144 | # Guidance Automation Toolkit 145 | *.gpState 146 | 147 | # ReSharper is a .NET coding add-in 148 | _ReSharper*/ 149 | *.[Rr]e[Ss]harper 150 | *.DotSettings.user 151 | 152 | # JustCode is a .NET coding add-in 153 | .JustCode 154 | 155 | # TeamCity is a build add-in 156 | _TeamCity* 157 | 158 | # DotCover is a Code Coverage Tool 159 | *.dotCover 160 | 161 | # AxoCover is a Code Coverage Tool 162 | .axoCover/* 163 | !.axoCover/settings.json 164 | 165 | # Visual Studio code coverage results 166 | *.coverage 167 | *.coveragexml 168 | 169 | # NCrunch 170 | _NCrunch_* 171 | .*crunch*.local.xml 172 | nCrunchTemp_* 173 | 174 | # MightyMoose 175 | *.mm.* 176 | AutoTest.Net/ 177 | 178 | # Web workbench (sass) 179 | .sass-cache/ 180 | 181 | # Installshield output folder 182 | [Ee]xpress/ 183 | 184 | # DocProject is a documentation generator add-in 185 | DocProject/buildhelp/ 186 | DocProject/Help/*.HxT 187 | DocProject/Help/*.HxC 188 | DocProject/Help/*.hhc 189 | DocProject/Help/*.hhk 190 | DocProject/Help/*.hhp 191 | DocProject/Help/Html2 192 | DocProject/Help/html 193 | 194 | # Click-Once directory 195 | publish/ 196 | 197 | # Publish Web Output 198 | *.[Pp]ublish.xml 199 | *.azurePubxml 200 | # Note: Comment the next line if you want to checkin your web deploy settings, 201 | # but database connection strings (with potential passwords) will be unencrypted 202 | *.pubxml 203 | *.publishproj 204 | 205 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 206 | # checkin your Azure Web App publish settings, but sensitive information contained 207 | # in these scripts will be unencrypted 208 | PublishScripts/ 209 | 210 | # NuGet Packages 211 | *.nupkg 212 | # NuGet Symbol Packages 213 | *.snupkg 214 | # The packages folder can be ignored because of Package Restore 215 | **/[Pp]ackages/* 216 | # except build/, which is used as an MSBuild target. 217 | !**/[Pp]ackages/build/ 218 | # Uncomment if necessary however generally it will be regenerated when needed 219 | #!**/[Pp]ackages/repositories.config 220 | # NuGet v3's project.json files produces more ignorable files 221 | *.nuget.props 222 | *.nuget.targets 223 | 224 | # Microsoft Azure Build Output 225 | csx/ 226 | *.build.csdef 227 | 228 | # Microsoft Azure Emulator 229 | ecf/ 230 | rcf/ 231 | 232 | # Windows Store app package directories and files 233 | AppPackages/ 234 | BundleArtifacts/ 235 | Package.StoreAssociation.xml 236 | _pkginfo.txt 237 | *.appx 238 | *.appxbundle 239 | *.appxupload 240 | 241 | # Visual Studio cache files 242 | # files ending in .cache can be ignored 243 | *.[Cc]ache 244 | # but keep track of directories ending in .cache 245 | !?*.[Cc]ache/ 246 | 247 | # Others 248 | ClientBin/ 249 | ~$* 250 | *~ 251 | *.dbmdl 252 | *.dbproj.schemaview 253 | *.jfm 254 | *.pfx 255 | *.publishsettings 256 | orleans.codegen.cs 257 | 258 | # Including strong name files can present a security risk 259 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 260 | #*.snk 261 | 262 | # Since there are multiple workflows, uncomment next line to ignore bower_components 263 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 264 | #bower_components/ 265 | 266 | # RIA/Silverlight projects 267 | Generated_Code/ 268 | 269 | # Backup & report files from converting an old project file 270 | # to a newer Visual Studio version. Backup files are not needed, 271 | # because we have git ;-) 272 | _UpgradeReport_Files/ 273 | Backup*/ 274 | UpgradeLog*.XML 275 | UpgradeLog*.htm 276 | ServiceFabricBackup/ 277 | *.rptproj.bak 278 | 279 | # SQL Server files 280 | *.mdf 281 | *.ldf 282 | *.ndf 283 | 284 | # Business Intelligence projects 285 | *.rdl.data 286 | *.bim.layout 287 | *.bim_*.settings 288 | *.rptproj.rsuser 289 | *- [Bb]ackup.rdl 290 | *- [Bb]ackup ([0-9]).rdl 291 | *- [Bb]ackup ([0-9][0-9]).rdl 292 | 293 | # Microsoft Fakes 294 | FakesAssemblies/ 295 | 296 | # GhostDoc plugin setting file 297 | *.GhostDoc.xml 298 | 299 | # Node.js Tools for Visual Studio 300 | .ntvs_analysis.dat 301 | node_modules/ 302 | 303 | # Visual Studio 6 build log 304 | *.plg 305 | 306 | # Visual Studio 6 workspace options file 307 | *.opt 308 | 309 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 310 | *.vbw 311 | 312 | # Visual Studio LightSwitch build output 313 | **/*.HTMLClient/GeneratedArtifacts 314 | **/*.DesktopClient/GeneratedArtifacts 315 | **/*.DesktopClient/ModelManifest.xml 316 | **/*.Server/GeneratedArtifacts 317 | **/*.Server/ModelManifest.xml 318 | _Pvt_Extensions 319 | 320 | # Paket dependency manager 321 | .paket/paket.exe 322 | paket-files/ 323 | 324 | # FAKE - F# Make 325 | .fake/ 326 | 327 | # CodeRush personal settings 328 | .cr/personal 329 | 330 | # Python Tools for Visual Studio (PTVS) 331 | __pycache__/ 332 | *.pyc 333 | 334 | # Cake - Uncomment if you are using it 335 | # tools/** 336 | # !tools/packages.config 337 | 338 | # Tabs Studio 339 | *.tss 340 | 341 | # Telerik's JustMock configuration file 342 | *.jmconfig 343 | 344 | # BizTalk build output 345 | *.btp.cs 346 | *.btm.cs 347 | *.odx.cs 348 | *.xsd.cs 349 | 350 | # OpenCover UI analysis results 351 | OpenCover/ 352 | 353 | # Azure Stream Analytics local run output 354 | ASALocalRun/ 355 | 356 | # MSBuild Binary and Structured Log 357 | *.binlog 358 | 359 | # NVidia Nsight GPU debugger configuration file 360 | *.nvuser 361 | 362 | # MFractors (Xamarin productivity tool) working folder 363 | .mfractor/ 364 | 365 | # Local History for Visual Studio 366 | .localhistory/ 367 | 368 | # BeatPulse healthcheck temp database 369 | healthchecksdb 370 | 371 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 372 | MigrationBackup/ 373 | 374 | # End of https://www.gitignore.io/api/monodevelop,visualstudio,visualstudiocode -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # lock distribution 2 | dist: trusty 3 | 4 | language: csharp 5 | solution: HttpSimulator.sln 6 | env: 7 | global: 8 | - EnableNuGetPackageRestore=true 9 | install: 10 | - nuget restore HttpSimulator.sln 11 | - nuget install NUnit.Runners -Version 2.6.4 -OutputDirectory testrunner 12 | script: 13 | - xbuild /p:Configuration=Release HttpSimulator.sln 14 | - mono ./testrunner/NUnit.Runners.2.6.4/tools/nunit-console.exe ./HttpSimulator.Tests/bin/Release/HttpSimulator.Tests.dll 15 | mono: 16 | - latest 17 | - 3.12.0 18 | - 3.10.0 19 | 20 | -------------------------------------------------------------------------------- /HttpSimulator.Tests/HttpSimulator.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.50727 7 | 2.0 8 | {7F177AF2-8C76-4E3C-93AA-C0EA5D23733F} 9 | Library 10 | HttpSimulatorTests 11 | HttpSimulator.Tests 12 | v4.0 13 | 14 | 15 | 16 | 17 | 2.0 18 | 19 | false 20 | publish\ 21 | true 22 | Disk 23 | false 24 | Foreground 25 | 7 26 | Days 27 | false 28 | false 29 | true 30 | 0 31 | 1.0.0.%2a 32 | false 33 | true 34 | 35 | 36 | true 37 | full 38 | false 39 | bin\Debug 40 | DEBUG; 41 | prompt 42 | 4 43 | false 44 | AllRules.ruleset 45 | 46 | 47 | full 48 | true 49 | bin\Release 50 | prompt 51 | 4 52 | false 53 | AllRules.ruleset 54 | 55 | 56 | 57 | ..\packages\NUnit.2.6.4\lib\nunit.framework.dll 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {CE9FFE92-9A64-483C-9F11-A27F83C0E14C} 69 | HttpSimulator 70 | 71 | 72 | 73 | 74 | False 75 | .NET Framework 3.5 SP1 Client Profile 76 | false 77 | 78 | 79 | False 80 | .NET Framework 3.5 SP1 81 | true 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /HttpSimulator.Tests/Test.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.IO; 4 | using System.Security.Principal; 5 | using NUnit.Framework; 6 | using Http.TestLibrary; 7 | using System.Web; 8 | 9 | namespace HttpSimulatorTests 10 | { 11 | [TestFixture] 12 | public class Test 13 | { 14 | [Test] 15 | public void CurrentIsNotNull() 16 | { 17 | using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest()) 18 | { 19 | Assert.IsNotNull(HttpContext.Current); 20 | } 21 | } 22 | 23 | [Test] 24 | public void RequestsAreLocalByDefault() 25 | { 26 | using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest()) 27 | { 28 | Assert.IsTrue(HttpContext.Current.Request.IsLocal); 29 | } 30 | } 31 | 32 | [Test] 33 | public void CanSimulateRemoteRequests() 34 | { 35 | using (var simulator = new HttpSimulator()) 36 | { 37 | simulator.SetIsLocalRequest(false) 38 | .SimulateRequest(new Uri("http://something.com/Test.aspx"), HttpVerb.GET); 39 | 40 | Assert.IsFalse(HttpContext.Current.Request.IsLocal); 41 | } 42 | } 43 | 44 | /// 45 | /// Determines whether this instance [can get set session]. 46 | /// 47 | [Test] 48 | public void CanGetSetSession() 49 | { 50 | using (var simulator = new HttpSimulator("/", @"c:\inetpub\").SimulateRequest()) 51 | { 52 | simulator.Context.Session["Test"] = "Success"; 53 | Assert.AreEqual("Success", simulator.Context.Session["Test"]); 54 | } 55 | } 56 | 57 | [Test] 58 | public void CanSimulateFormGetWithQueryString() 59 | { 60 | using (var simulator = new HttpSimulator()) 61 | { 62 | var form = new NameValueCollection(); 63 | form.Add("Test1", "Value1"); 64 | form.Add("Test2", "Value2"); 65 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx?Test1=Value1&Test2=Value2")); 66 | Assert.AreEqual(form, simulator.Context.Request.QueryString); 67 | } 68 | } 69 | 70 | /// 71 | /// Determines whether this instance [can simulate form post]. 72 | /// 73 | [Test] 74 | public void CanSimulateFormPost() 75 | { 76 | using (var simulator = new HttpSimulator()) 77 | { 78 | var form = new NameValueCollection(); 79 | form.Add("Test1", "Value1"); 80 | form.Add("Test2", "Value2"); 81 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), form); 82 | 83 | Assert.AreEqual("Value1", simulator.Context.Request.Form["Test1"]); 84 | Assert.AreEqual("Value2", simulator.Context.Request.Form["Test2"]); 85 | Assert.AreEqual(new Uri("http://localhost/Test.aspx"), simulator.Context.Request.Url); 86 | } 87 | 88 | using (var simulator = new HttpSimulator()) 89 | { 90 | simulator.SetFormVariable("Test1", "Value1") 91 | .SetFormVariable("Test2", "Value2") 92 | .SimulateRequest(new Uri("http://localhost/Test.aspx")); 93 | 94 | Assert.AreEqual("Value1", simulator.Context.Request.Form["Test1"]); 95 | Assert.AreEqual("Value2", simulator.Context.Request.Form["Test2"]); 96 | Assert.AreEqual(new Uri("http://localhost/Test.aspx"), simulator.Context.Request.Url); 97 | } 98 | } 99 | 100 | [Test] 101 | public void CanSimulateSession() 102 | { 103 | using (var simulator = new HttpSimulator()) 104 | { 105 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx")); 106 | 107 | Assert.IsNotNull(simulator.Context.Session.SessionID); 108 | simulator.Context.Session.Add("item", "value"); 109 | Assert.AreEqual(1, simulator.Context.Session.Count); 110 | Assert.AreEqual("value", simulator.Context.Session["item"]); 111 | } 112 | } 113 | 114 | [Test] 115 | public void CanSimulateUserAgent() { 116 | using (var simulator = new HttpSimulator()) { 117 | var headers = new NameValueCollection(); 118 | headers.Add("User-Agent", "Agent1"); 119 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), HttpVerb.POST, headers); 120 | Assert.AreEqual("Agent1", simulator.Context.Request.UserAgent); 121 | } 122 | } 123 | 124 | [Test] 125 | [Platform(Exclude = "Mono")] 126 | public void CanSimulateCookie() 127 | { 128 | using (var simulator = new HttpSimulator()) 129 | { 130 | var headers = new NameValueCollection(); 131 | headers.Add("Cookie", "Cookie1=Value1"); 132 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), HttpVerb.POST, headers); 133 | Assert.AreEqual("Value1", HttpContext.Current.Request.Cookies["Cookie1"].Value); 134 | } 135 | } 136 | 137 | [Test] 138 | [Platform(Exclude = "Mono")] 139 | public void CanSimulateBrowser() 140 | { 141 | using (var simulator = new HttpSimulator()) 142 | { 143 | simulator.SetBrowser("browser", "IE"); 144 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), HttpVerb.GET); 145 | Assert.NotNull(HttpContext.Current.Request.Browser); 146 | Assert.AreEqual("IE", HttpContext.Current.Request.Browser.Capabilities["browser"]); 147 | } 148 | } 149 | 150 | [Test] 151 | [Platform(Exclude = "Mono")] 152 | public void CanSimulateIdentity() 153 | { 154 | var id = new WindowsIdentity(WindowsIdentity.GetCurrent().Token, 155 | "Negotiate", WindowsAccountType.Normal, true); 156 | 157 | using (var simulator = new HttpSimulator()) 158 | { 159 | simulator.SetIdentity(id); 160 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), HttpVerb.GET); 161 | Assert.NotNull(HttpContext.Current.Request.LogonUserIdentity); 162 | Assert.AreEqual("Negotiate", HttpContext.Current.Request.LogonUserIdentity.AuthenticationType); 163 | Assert.IsNotEmpty(HttpContext.Current.Request.LogonUserIdentity.Name); 164 | } 165 | } 166 | 167 | [Test] 168 | [Platform(Exclude = "Mono")] 169 | public void CanSimulateResponseHeaders() 170 | { 171 | using (var simulator = new HttpSimulator()) 172 | { 173 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), HttpVerb.GET); 174 | HttpContext.Current.Response.AppendHeader("X-Content-Security-Policy", "frame-ancestors 'self'"); 175 | HttpContext.Current.Response.Flush(); 176 | Assert.IsNotEmpty(simulator.ResponseHeaders); 177 | Assert.That(simulator.ResponseHeaders, Contains.Substring("X-Content-Security-Policy: frame-ancestors 'self'")); 178 | } 179 | } 180 | 181 | [Test] 182 | [Platform(Exclude = "Mono")] 183 | public void CanGetSetCookies() { 184 | using (var simulator = new HttpSimulator()) 185 | { 186 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), HttpVerb.POST); 187 | simulator.Context.Response.Cookies.Add(new HttpCookie("a", "b")); 188 | Assert.AreEqual("b", HttpContext.Current.Response.Cookies["a"].Value); 189 | } 190 | } 191 | 192 | [Test] 193 | [Platform(Exclude = "Mono")] 194 | public void CanSimulateMapPath() 195 | { 196 | using (var simulator = new HttpSimulator()) 197 | { 198 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx")); 199 | 200 | Assert.AreEqual("c:\\InetPub\\wwwRoot\\test\\test.js", simulator.Context.Server.MapPath("~/test/test.js")); 201 | Assert.AreEqual("c:\\InetPub\\wwwRoot\\test.js", simulator.Context.Server.MapPath("test.js")); 202 | } 203 | } 204 | 205 | /// 206 | /// Determines whether this instance [can simulate form post]. 207 | /// 208 | [Test] 209 | [Platform(Exclude = "Mono")] 210 | public void CanSimulateFormPostOnHttpContext() 211 | { 212 | using (var simulator = new HttpSimulator()) 213 | { 214 | var form = new NameValueCollection(); 215 | form.Add("Test1", "Value1"); 216 | form.Add("Test2", "Value2"); 217 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), form); 218 | 219 | Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]); 220 | Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]); 221 | Assert.AreEqual(new Uri("http://localhost/Test.aspx"), HttpContext.Current.Request.Url); 222 | } 223 | 224 | using (var simulator = new HttpSimulator()) 225 | { 226 | simulator.SetFormVariable("Test1", "Value1") 227 | .SetFormVariable("Test2", "Value2") 228 | .SimulateRequest(new Uri("http://localhost/Test.aspx")); 229 | 230 | Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]); 231 | Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]); 232 | Assert.AreEqual(new Uri("http://localhost/Test.aspx"), HttpContext.Current.Request.Url); 233 | } 234 | } 235 | 236 | [Test] 237 | [Platform(Exclude = "Mono")] 238 | public void CanWriteDebugInfoToSpecifiedWriter() 239 | { 240 | using (var debugWriter = new StringWriter()) 241 | { 242 | using (var simulator = new HttpSimulator()) 243 | { 244 | simulator.DebugWriter = debugWriter; 245 | 246 | simulator.SimulateRequest(); 247 | 248 | Assert.IsNotNullOrEmpty(debugWriter.ToString(), "Debug output"); 249 | } 250 | } 251 | } 252 | 253 | [Test] 254 | [Platform(Exclude = "Mono")] 255 | public void CanDisableWritingDebugInfoToConsole() 256 | { 257 | using (var console = new ConsoleCapture()) 258 | { 259 | using (var simulator = new HttpSimulator()) 260 | { 261 | simulator.DebugWriter = TextWriter.Null; 262 | simulator.SimulateRequest(); 263 | Assert.IsEmpty(console.Out.ToString(), "Console.Out output"); 264 | } 265 | } 266 | } 267 | 268 | /// 269 | /// Captures ouput that would go to the console. 270 | /// 271 | private class ConsoleCapture : IDisposable 272 | { 273 | private readonly TextWriter savedStdOut; 274 | private readonly TextWriter savedStdErr; 275 | 276 | public TextWriter Out { get; private set; } = new StringWriter(); 277 | 278 | public TextWriter Error { get; private set; } = new StringWriter(); 279 | 280 | 281 | public ConsoleCapture() 282 | { 283 | savedStdOut = Console.Out; 284 | savedStdErr = Console.Error; 285 | 286 | Console.SetOut(Out); 287 | Console.SetError(Error); 288 | } 289 | 290 | public void Dispose() 291 | { 292 | Console.SetOut(savedStdOut); 293 | Console.SetError(savedStdErr); 294 | 295 | Out?.Dispose(); 296 | Out = null; 297 | Error?.Dispose(); 298 | Error = null; 299 | } 300 | } 301 | } 302 | } 303 | 304 | -------------------------------------------------------------------------------- /HttpSimulator.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /HttpSimulator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26403.7 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpSimulator", "HttpSimulator\HttpSimulator.csproj", "{CE9FFE92-9A64-483C-9F11-A27F83C0E14C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpSimulator.Tests", "HttpSimulator.Tests\HttpSimulator.Tests.csproj", "{7F177AF2-8C76-4E3C-93AA-C0EA5D23733F}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {CE9FFE92-9A64-483C-9F11-A27F83C0E14C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {CE9FFE92-9A64-483C-9F11-A27F83C0E14C}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {CE9FFE92-9A64-483C-9F11-A27F83C0E14C}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {CE9FFE92-9A64-483C-9F11-A27F83C0E14C}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {7F177AF2-8C76-4E3C-93AA-C0EA5D23733F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {7F177AF2-8C76-4E3C-93AA-C0EA5D23733F}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {7F177AF2-8C76-4E3C-93AA-C0EA5D23733F}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {7F177AF2-8C76-4E3C-93AA-C0EA5D23733F}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /HttpSimulator/BaseWrapped/HttpContext.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Web; 3 | 4 | namespace Http.TestLibrary.BaseWrapped 5 | { 6 | internal class HttpContext : HttpContextBase 7 | { 8 | private readonly HttpRequestBase _workerRequest; 9 | private readonly HttpSessionStateBase _fakeHttpSessionState; 10 | private readonly HttpServerUtility _fakeHttpServerUtility; 11 | private readonly HttpResponseBase _fakeHttpResponse; 12 | 13 | public HttpContext(HttpRequestBase workerRequest, HttpSessionStateBase fakeHttpSessionState, HttpServerUtility fakeHttpServerUtility, HttpResponse response) 14 | { 15 | _workerRequest = workerRequest; 16 | _fakeHttpSessionState = fakeHttpSessionState; 17 | _fakeHttpServerUtility = fakeHttpServerUtility; 18 | _fakeHttpResponse = new HttpResponseWrapper(response); 19 | } 20 | 21 | public override HttpSessionStateBase Session 22 | { 23 | get { return _fakeHttpSessionState; } 24 | } 25 | 26 | public override HttpRequestBase Request 27 | { 28 | get { return _workerRequest; } 29 | } 30 | 31 | public override HttpServerUtilityBase Server 32 | { 33 | get { return _fakeHttpServerUtility; } 34 | } 35 | 36 | public override HttpResponseBase Response { 37 | get { 38 | return _fakeHttpResponse; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /HttpSimulator/BaseWrapped/HttpServerUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | 3 | namespace Http.TestLibrary.BaseWrapped 4 | { 5 | internal class HttpServerUtility : HttpServerUtilityBase 6 | { 7 | private readonly HttpSimulator.ConfigMapPath _configMap; 8 | 9 | public HttpServerUtility(HttpSimulator.ConfigMapPath configMap) 10 | { 11 | _configMap = configMap; 12 | } 13 | 14 | public override string MapPath(string path) 15 | { 16 | return _configMap.MapPath(string.Empty, path); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /HttpSimulator/BaseWrapped/HttpSessionState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.Web; 4 | using System.Web.SessionState; 5 | 6 | namespace Http.TestLibrary.BaseWrapped 7 | { 8 | internal class HttpSessionState : HttpSessionStateBase 9 | { 10 | private HttpSimulator.FakeHttpSessionState session; 11 | 12 | public HttpSessionState(HttpSimulator.FakeHttpSessionState session) 13 | { 14 | this.session = session; 15 | } 16 | 17 | /// 18 | ///Ends the current session. 19 | /// 20 | /// 21 | public override void Abandon() 22 | { 23 | session.Abandon(); 24 | } 25 | 26 | /// 27 | ///Adds a new item to the session-state collection. 28 | /// 29 | /// 30 | ///The name of the item to add to the session-state collection. 31 | ///The value of the item to add to the session-state collection. 32 | public override void Add(string name, object value) 33 | { 34 | session.Add(name, value); 35 | } 36 | 37 | /// 38 | ///Deletes an item from the session-state item collection. 39 | /// 40 | /// 41 | ///The name of the item to delete from the session-state item collection. 42 | public override void Remove(string name) 43 | { 44 | session.Remove(name); 45 | } 46 | 47 | /// 48 | ///Deletes an item at a specified index from the session-state item collection. 49 | /// 50 | /// 51 | ///The index of the item to remove from the session-state collection. 52 | public override void RemoveAt(int index) 53 | { 54 | session.RemoveAt(index); 55 | } 56 | 57 | /// 58 | ///Clears all values from the session-state item collection. 59 | /// 60 | /// 61 | public override void Clear() 62 | { 63 | session.Clear(); 64 | } 65 | 66 | /// 67 | ///Clears all values from the session-state item collection. 68 | /// 69 | /// 70 | public override void RemoveAll() 71 | { 72 | session.RemoveAll(); 73 | } 74 | 75 | /// 76 | ///Copies the collection of session-state item values to a one-dimensional array, starting at the specified index in the array. 77 | /// 78 | /// 79 | ///The that receives the session values. 80 | ///The index in array where copying starts. 81 | public override void CopyTo(Array array, int index) 82 | { 83 | throw new NotImplementedException(); 84 | } 85 | 86 | /// 87 | ///Gets the unique session identifier for the session. 88 | /// 89 | /// 90 | /// 91 | ///The session ID. 92 | /// 93 | /// 94 | public override string SessionID 95 | { 96 | get { return session.SessionID; } 97 | } 98 | 99 | /// 100 | ///Gets and sets the time-out period (in minutes) allowed between requests before the session-state provider terminates the session. 101 | /// 102 | /// 103 | /// 104 | ///The time-out period, in minutes. 105 | /// 106 | /// 107 | public override int Timeout 108 | { 109 | get { return session.Timeout; } 110 | set { session.Timeout = value; } 111 | } 112 | 113 | /// 114 | ///Gets a value indicating whether the session was created with the current request. 115 | /// 116 | /// 117 | /// 118 | ///true if the session was created with the current request; otherwise, false. 119 | /// 120 | /// 121 | public override bool IsNewSession 122 | { 123 | get { return session.IsNewSession; } 124 | } 125 | 126 | /// 127 | ///Gets the current session-state mode. 128 | /// 129 | /// 130 | /// 131 | ///One of the values. 132 | /// 133 | /// 134 | public override SessionStateMode Mode 135 | { 136 | get { return session.Mode; } 137 | } 138 | 139 | /// 140 | ///Gets a value indicating whether the session ID is embedded in the URL or stored in an HTTP cookie. 141 | /// 142 | /// 143 | /// 144 | ///true if the session is embedded in the URL; otherwise, false. 145 | /// 146 | /// 147 | public override bool IsCookieless 148 | { 149 | get { return session.IsCookieless; } 150 | } 151 | 152 | /// 153 | ///Gets a value that indicates whether the application is configured for cookieless sessions. 154 | /// 155 | /// 156 | /// 157 | ///One of the values that indicate whether the application is configured for cookieless sessions. The default is . 158 | /// 159 | /// 160 | public override HttpCookieMode CookieMode 161 | { 162 | get { return session.CookieMode; } 163 | } 164 | 165 | /// 166 | ///Gets or sets the locale identifier (LCID) of the current session. 167 | /// 168 | /// 169 | /// 170 | ///A instance that specifies the culture of the current session. 171 | /// 172 | /// 173 | public override int LCID 174 | { 175 | get { return session.LCID; } 176 | set { session.LCID = value; } 177 | } 178 | 179 | /// 180 | ///Gets or sets the code-page identifier for the current session. 181 | /// 182 | /// 183 | /// 184 | ///The code-page identifier for the current session. 185 | /// 186 | /// 187 | public override int CodePage 188 | { 189 | get { return session.CodePage; } 190 | set { session.CodePage = value; } 191 | } 192 | 193 | /// 194 | ///Gets a collection of objects declared by <object Runat="Server" Scope="Session"/> tags within the ASP.NET application file Global.asax. 195 | /// 196 | /// 197 | /// 198 | ///An containing objects declared in the Global.asax file. 199 | /// 200 | /// 201 | public override HttpStaticObjectsCollectionBase StaticObjects 202 | { 203 | get 204 | { 205 | throw new NotImplementedException(); 206 | //return session.StaticObjects; 207 | } 208 | } 209 | 210 | /// 211 | ///Gets or sets a session-state item value by name. 212 | /// 213 | /// 214 | /// 215 | ///The session-state item value specified in the name parameter. 216 | /// 217 | /// 218 | ///The key name of the session-state item value. 219 | public override object this [string name] 220 | { 221 | get { return session[name]; } 222 | set { session[name] = value; } 223 | } 224 | 225 | /// 226 | ///Gets or sets a session-state item value by numerical index. 227 | /// 228 | /// 229 | /// 230 | ///The session-state item value specified in the index parameter. 231 | /// 232 | /// 233 | ///The numerical index of the session-state item value. 234 | public override object this [int index] 235 | { 236 | get { return session[index]; } 237 | set { session[index] = value; } 238 | } 239 | 240 | /// 241 | ///Gets an object that can be used to synchronize access to the collection of session-state values. 242 | /// 243 | /// 244 | /// 245 | ///An object that can be used to synchronize access to the collection. 246 | /// 247 | /// 248 | public override object SyncRoot 249 | { 250 | get { return session.SyncRoot; } 251 | } 252 | 253 | /// 254 | ///Gets a value indicating whether access to the collection of session-state values is synchronized (thread safe). 255 | /// 256 | /// 257 | ///true if access to the collection is synchronized (thread safe); otherwise, false. 258 | /// 259 | /// 260 | public override bool IsSynchronized 261 | { 262 | get { return session.IsSynchronized; } 263 | } 264 | 265 | public override int Count 266 | { 267 | get { return session.Count; } 268 | } 269 | 270 | public override bool IsReadOnly 271 | { 272 | get { return session.GetIsReadOnly(); } 273 | } 274 | 275 | public override NameObjectCollectionBase.KeysCollection Keys 276 | { 277 | get { return session.Keys; } 278 | } 279 | 280 | } 281 | } -------------------------------------------------------------------------------- /HttpSimulator/BaseWrapped/SimulatedHttpRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.Web; 4 | 5 | namespace Http.TestLibrary.BaseWrapped 6 | { 7 | internal class SimulatedHttpRequest:HttpRequestBase 8 | { 9 | private readonly TestLibrary.SimulatedHttpRequest _request; 10 | 11 | internal void SetReferer(Uri referer) 12 | { 13 | _request.SetReferer(referer); 14 | } 15 | 16 | /// 17 | /// Returns the specified member of the request header. 18 | /// 19 | /// 20 | /// The HTTP verb returned in the request 21 | /// header. 22 | /// 23 | public override string HttpMethod 24 | { 25 | get { return _request.GetHttpVerbName(); } 26 | } 27 | 28 | 29 | /// 30 | /// Gets the name of the server. 31 | /// 32 | /// 33 | public string GetServerName() 34 | { 35 | return _request.GetServerName(); 36 | } 37 | 38 | public int GetLocalPort() 39 | { 40 | return _request.GetLocalPort(); 41 | } 42 | 43 | /// 44 | /// Gets the headers. 45 | /// 46 | /// The headers. 47 | public override NameValueCollection Headers 48 | { 49 | get 50 | { 51 | return _request.Headers; 52 | } 53 | } 54 | 55 | 56 | /// 57 | /// Gets the format exception. 58 | /// 59 | /// The format exception. 60 | public override NameValueCollection Form 61 | { 62 | get 63 | { 64 | return _request.Form; 65 | } 66 | } 67 | 68 | public override NameValueCollection QueryString 69 | { 70 | get 71 | { 72 | return HttpUtility.ParseQueryString(_request.GetQueryString()); 73 | } 74 | 75 | } 76 | 77 | public SimulatedHttpRequest(TestLibrary.SimulatedHttpRequest request) 78 | { 79 | _request = request; 80 | } 81 | 82 | /// 83 | /// Returns the virtual path to the currently executing 84 | /// server application. 85 | /// 86 | /// 87 | /// The virtual path of the current application. 88 | /// 89 | public override string ApplicationPath 90 | { 91 | get { return _request.GetAppPath(); } 92 | } 93 | 94 | public override string PhysicalApplicationPath 95 | { 96 | get { return _request.GetAppPathTranslated(); } 97 | } 98 | 99 | public override Uri Url 100 | { 101 | get { return _request.Uri; } 102 | } 103 | 104 | 105 | public override string UserAgent { 106 | get { 107 | return _request.GetKnownRequestHeader(HttpWorkerRequest.HeaderUserAgent); 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /HttpSimulator/HttpSimulator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.IO; 4 | using System.Security.Principal; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Web; 8 | using System.Web.Configuration; 9 | using System.Web.Hosting; 10 | using System.Web.SessionState; 11 | using Http.TestLibrary.BaseWrapped; 12 | using HttpContext = Http.TestLibrary.BaseWrapped.HttpContext; 13 | using HttpSessionState = Http.TestLibrary.BaseWrapped.HttpSessionState; 14 | 15 | namespace Http.TestLibrary 16 | { 17 | public enum HttpVerb 18 | { 19 | GET, 20 | HEAD, 21 | POST, 22 | PUT, 23 | DELETE, 24 | } 25 | 26 | /// 27 | /// Useful class for simulating the HttpContext. This does not actually 28 | /// make an HttpRequest, it merely simulates the state that your code 29 | /// would be in "as if" handling a request. Thus the HttpContext.Current 30 | /// property is populated. 31 | /// 32 | public class HttpSimulator : IDisposable 33 | { 34 | private const string defaultPhysicalAppPath = @"c:\InetPub\wwwRoot\"; 35 | private StringBuilder builder; 36 | private Uri _referer; 37 | private bool _isLocalRequest = true; 38 | private NameValueCollection _formVars = new NameValueCollection(); 39 | private NameValueCollection _headers = new NameValueCollection(); 40 | private NameValueCollection _browser = new NameValueCollection(); 41 | private WindowsIdentity _identity; 42 | private TextWriter debugWriter = Console.Out; 43 | 44 | public HttpSimulator() 45 | : this("/", defaultPhysicalAppPath) 46 | { 47 | } 48 | 49 | public HttpSimulator(string applicationPath) 50 | : this(applicationPath, defaultPhysicalAppPath) 51 | { 52 | } 53 | 54 | public HttpSimulator(string applicationPath, string physicalApplicationPath) 55 | { 56 | this.ApplicationPath = applicationPath; 57 | this.PhysicalApplicationPath = physicalApplicationPath; 58 | } 59 | 60 | /// 61 | /// Sets up the HttpContext objects to simulate a GET request. 62 | /// 63 | /// 64 | /// Simulates a request to http://localhost/ 65 | /// 66 | public HttpSimulator SimulateRequest() 67 | { 68 | return SimulateRequest(new Uri("http://localhost/")); 69 | } 70 | 71 | /// 72 | /// Sets up the HttpContext objects to simulate a GET request. 73 | /// 74 | /// 75 | public HttpSimulator SimulateRequest(Uri url) 76 | { 77 | return SimulateRequest(url, HttpVerb.GET); 78 | } 79 | 80 | /// 81 | /// Sets up the HttpContext objects to simulate a request. 82 | /// 83 | /// 84 | /// 85 | public HttpSimulator SimulateRequest(Uri url, HttpVerb httpVerb) 86 | { 87 | return SimulateRequest(url, httpVerb, null, null); 88 | } 89 | 90 | /// 91 | /// Sets up the HttpContext objects to simulate a POST request. 92 | /// 93 | /// 94 | /// 95 | public HttpSimulator SimulateRequest(Uri url, NameValueCollection formVariables) 96 | { 97 | return SimulateRequest(url, HttpVerb.POST, formVariables, null); 98 | } 99 | 100 | /// 101 | /// Sets up the HttpContext objects to simulate a POST request. 102 | /// 103 | /// 104 | /// 105 | /// 106 | public HttpSimulator SimulateRequest(Uri url, NameValueCollection formVariables, NameValueCollection headers) 107 | { 108 | return SimulateRequest(url, HttpVerb.POST, formVariables, headers); 109 | } 110 | 111 | /// 112 | /// Sets up the HttpContext objects to simulate a request. 113 | /// 114 | /// 115 | /// 116 | /// 117 | public HttpSimulator SimulateRequest(Uri url, HttpVerb httpVerb, NameValueCollection headers) 118 | { 119 | return SimulateRequest(url, httpVerb, null, headers); 120 | } 121 | 122 | /// 123 | /// Sets up the HttpContext objects to simulate a request. 124 | /// 125 | /// 126 | /// 127 | /// 128 | /// 129 | protected virtual HttpSimulator SimulateRequest(Uri url, HttpVerb httpVerb, NameValueCollection formVariables, NameValueCollection headers) 130 | { 131 | System.Web.HttpContext.Current = null; 132 | 133 | ParseRequestUrl(url); 134 | 135 | if (this.responseWriter == null) 136 | { 137 | this.builder = new StringBuilder(); 138 | this.responseWriter = new StringWriter(builder); 139 | } 140 | 141 | _responseHeadersBuilder = new StringBuilder(); 142 | 143 | SetHttpRuntimeInternals(); 144 | 145 | string query = ExtractQueryStringPart(url); 146 | 147 | if (formVariables != null) 148 | _formVars.Add(formVariables); 149 | 150 | if (_formVars.Count > 0) 151 | httpVerb = HttpVerb.POST; //Need to enforce this. 152 | 153 | if (headers != null) 154 | _headers.Add(headers); 155 | 156 | this.workerRequest = new SimulatedHttpRequest(ApplicationPath, PhysicalApplicationPath, PhysicalPath, Page, query, this.responseWriter, host, port, httpVerb.ToString(), url, _responseHeadersBuilder); 157 | 158 | this.workerRequest.Form.Add(_formVars); 159 | this.workerRequest.Headers.Add(_headers); 160 | foreach(var key in _browser.AllKeys) 161 | this.workerRequest.Browser.Capabilities.Add(key, _browser.Get(key)); 162 | 163 | if (_referer != null) 164 | this.workerRequest.SetReferer(_referer); 165 | 166 | if (_identity != null) 167 | this.workerRequest.SetIdentity(_identity); 168 | 169 | this.workerRequest.SetIsLocalRequest(_isLocalRequest); 170 | 171 | InitializeSession(); 172 | 173 | InitializeApplication(); 174 | 175 | WriteDebugInfo(); 176 | 177 | return this; 178 | } 179 | 180 | /// 181 | /// Sets the to use for writing out debugging information. 182 | /// 183 | /// Set this to TextWriter.Null to disable debug output. 184 | /// 185 | /// 186 | /// By default, debug information is written out to the console. 187 | /// 188 | public TextWriter DebugWriter { set { debugWriter = value; } } 189 | 190 | private void WriteDebugInfo() 191 | { 192 | if (debugWriter == null) 193 | { 194 | return; 195 | } 196 | debugWriter.WriteLine("host: " + host); 197 | debugWriter.WriteLine("virtualDir: " + applicationPath); 198 | debugWriter.WriteLine("page: " + localPath); 199 | debugWriter.WriteLine("pathPartAfterApplicationPart: " + _page); 200 | debugWriter.WriteLine("appPhysicalDir: " + physicalApplicationPath); 201 | debugWriter.WriteLine("Request.Url.LocalPath: " + System.Web.HttpContext.Current.Request.Url.LocalPath); 202 | debugWriter.WriteLine("Request.Url.Host: " + System.Web.HttpContext.Current.Request.Url.Host); 203 | debugWriter.WriteLine("Request.FilePath: " + System.Web.HttpContext.Current.Request.FilePath); 204 | debugWriter.WriteLine("Request.Path: " + System.Web.HttpContext.Current.Request.Path); 205 | debugWriter.WriteLine("Request.RawUrl: " + System.Web.HttpContext.Current.Request.RawUrl); 206 | debugWriter.WriteLine("Request.Url: " + System.Web.HttpContext.Current.Request.Url); 207 | debugWriter.WriteLine("Request.Url.Port: " + System.Web.HttpContext.Current.Request.Url.Port); 208 | debugWriter.WriteLine("Request.ApplicationPath: " + System.Web.HttpContext.Current.Request.ApplicationPath); 209 | debugWriter.WriteLine("Request.PhysicalPath: " + System.Web.HttpContext.Current.Request.PhysicalPath); 210 | debugWriter.WriteLine("HttpRuntime.AppDomainAppPath: " + HttpRuntime.AppDomainAppPath); 211 | debugWriter.WriteLine("HttpRuntime.AppDomainAppVirtualPath: " + HttpRuntime.AppDomainAppVirtualPath); 212 | debugWriter.WriteLine("HostingEnvironment.ApplicationPhysicalPath: " + HostingEnvironment.ApplicationPhysicalPath); 213 | debugWriter.WriteLine("HostingEnvironment.ApplicationVirtualPath: " + HostingEnvironment.ApplicationVirtualPath); 214 | } 215 | 216 | private static void InitializeApplication() 217 | { 218 | Type appFactoryType = Type.GetType("System.Web.HttpApplicationFactory, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); 219 | object appFactory = ReflectionHelper.GetStaticFieldValue("_theApplicationFactory", appFactoryType); 220 | if (appFactory == null) 221 | return; 222 | ReflectionHelper.SetPrivateInstanceFieldValue("_state", appFactory, System.Web.HttpContext.Current.Application); 223 | } 224 | 225 | private void InitializeSession() 226 | { 227 | System.Web.HttpContext.Current = new System.Web.HttpContext(workerRequest); 228 | System.Web.HttpContext.Current.Items.Clear(); 229 | var fakeHttpSessionState = new FakeHttpSessionState(); 230 | System.Web.SessionState.HttpSessionState session = (System.Web.SessionState.HttpSessionState)ReflectionHelper.Instantiate(typeof(System.Web.SessionState.HttpSessionState), new Type[] { typeof(IHttpSessionState) }, fakeHttpSessionState); 231 | Context = new HttpContext(new BaseWrapped.SimulatedHttpRequest(workerRequest), 232 | new HttpSessionState(fakeHttpSessionState), 233 | new BaseWrapped.HttpServerUtility(new ConfigMapPath(this)), 234 | System.Web.HttpContext.Current.Response); 235 | 236 | System.Web.HttpContext.Current.Items.Add("AspSession", session); 237 | System.Web.HttpContext.Current.Request.Browser = workerRequest.Browser; 238 | } 239 | 240 | public class FakeHttpSessionState : NameObjectCollectionBase, IHttpSessionState 241 | { 242 | private string sessionID = Guid.NewGuid().ToString(); 243 | private int timeout = 30; 244 | //minutes 245 | private bool isNewSession = true; 246 | private int lcid; 247 | private int codePage; 248 | private HttpStaticObjectsCollection staticObjects = new HttpStaticObjectsCollection(); 249 | private object syncRoot = new Object(); 250 | 251 | /// 252 | ///Ends the current session. 253 | /// 254 | /// 255 | public void Abandon() 256 | { 257 | BaseClear(); 258 | } 259 | 260 | /// 261 | ///Adds a new item to the session-state collection. 262 | /// 263 | /// 264 | ///The name of the item to add to the session-state collection. 265 | ///The value of the item to add to the session-state collection. 266 | public void Add(string name, object value) 267 | { 268 | BaseAdd(name, value); 269 | } 270 | 271 | /// 272 | ///Deletes an item from the session-state item collection. 273 | /// 274 | /// 275 | ///The name of the item to delete from the session-state item collection. 276 | public void Remove(string name) 277 | { 278 | BaseRemove(name); 279 | } 280 | 281 | /// 282 | ///Deletes an item at a specified index from the session-state item collection. 283 | /// 284 | /// 285 | ///The index of the item to remove from the session-state collection. 286 | public void RemoveAt(int index) 287 | { 288 | BaseRemoveAt(index); 289 | } 290 | 291 | /// 292 | ///Clears all values from the session-state item collection. 293 | /// 294 | /// 295 | public void Clear() 296 | { 297 | BaseClear(); 298 | } 299 | 300 | /// 301 | ///Clears all values from the session-state item collection. 302 | /// 303 | /// 304 | public void RemoveAll() 305 | { 306 | BaseClear(); 307 | } 308 | 309 | /// 310 | ///Copies the collection of session-state item values to a one-dimensional array, starting at the specified index in the array. 311 | /// 312 | /// 313 | ///The that receives the session values. 314 | ///The index in array where copying starts. 315 | public void CopyTo(Array array, int index) 316 | { 317 | throw new NotImplementedException(); 318 | } 319 | 320 | /// 321 | ///Gets the unique session identifier for the session. 322 | /// 323 | /// 324 | /// 325 | ///The session ID. 326 | /// 327 | /// 328 | public string SessionID 329 | { 330 | get { return sessionID; } 331 | } 332 | 333 | /// 334 | ///Gets and sets the time-out period (in minutes) allowed between requests before the session-state provider terminates the session. 335 | /// 336 | /// 337 | /// 338 | ///The time-out period, in minutes. 339 | /// 340 | /// 341 | public int Timeout 342 | { 343 | get { return timeout; } 344 | set { timeout = value; } 345 | } 346 | 347 | /// 348 | ///Gets a value indicating whether the session was created with the current request. 349 | /// 350 | /// 351 | /// 352 | ///true if the session was created with the current request; otherwise, false. 353 | /// 354 | /// 355 | public bool IsNewSession 356 | { 357 | get { return isNewSession; } 358 | } 359 | 360 | /// 361 | ///Gets the current session-state mode. 362 | /// 363 | /// 364 | /// 365 | ///One of the values. 366 | /// 367 | /// 368 | public SessionStateMode Mode 369 | { 370 | get { return SessionStateMode.InProc; } 371 | } 372 | 373 | /// 374 | ///Gets a value indicating whether the session ID is embedded in the URL or stored in an HTTP cookie. 375 | /// 376 | /// 377 | /// 378 | ///true if the session is embedded in the URL; otherwise, false. 379 | /// 380 | /// 381 | public bool IsCookieless 382 | { 383 | get { return false; } 384 | } 385 | 386 | /// 387 | ///Gets a value that indicates whether the application is configured for cookieless sessions. 388 | /// 389 | /// 390 | /// 391 | ///One of the values that indicate whether the application is configured for cookieless sessions. The default is . 392 | /// 393 | /// 394 | public HttpCookieMode CookieMode 395 | { 396 | get { return HttpCookieMode.UseCookies; } 397 | } 398 | 399 | /// 400 | ///Gets or sets the locale identifier (LCID) of the current session. 401 | /// 402 | /// 403 | /// 404 | ///A instance that specifies the culture of the current session. 405 | /// 406 | /// 407 | public int LCID 408 | { 409 | get { return lcid; } 410 | set { lcid = value; } 411 | } 412 | 413 | /// 414 | ///Gets or sets the code-page identifier for the current session. 415 | /// 416 | /// 417 | /// 418 | ///The code-page identifier for the current session. 419 | /// 420 | /// 421 | public int CodePage 422 | { 423 | get { return codePage; } 424 | set { codePage = value; } 425 | } 426 | 427 | /// 428 | ///Gets a collection of objects declared by <object Runat="Server" Scope="Session"/> tags within the ASP.NET application file Global.asax. 429 | /// 430 | /// 431 | /// 432 | ///An containing objects declared in the Global.asax file. 433 | /// 434 | /// 435 | public HttpStaticObjectsCollection StaticObjects 436 | { 437 | get { return staticObjects; } 438 | } 439 | 440 | /// 441 | ///Gets or sets a session-state item value by name. 442 | /// 443 | /// 444 | /// 445 | ///The session-state item value specified in the name parameter. 446 | /// 447 | /// 448 | ///The key name of the session-state item value. 449 | public object this [string name] 450 | { 451 | get { return BaseGet(name); } 452 | set { BaseSet(name, value); } 453 | } 454 | 455 | /// 456 | ///Gets or sets a session-state item value by numerical index. 457 | /// 458 | /// 459 | /// 460 | ///The session-state item value specified in the index parameter. 461 | /// 462 | /// 463 | ///The numerical index of the session-state item value. 464 | public object this [int index] 465 | { 466 | get { return BaseGet(index); } 467 | set { BaseSet(index, value); } 468 | } 469 | 470 | /// 471 | ///Gets an object that can be used to synchronize access to the collection of session-state values. 472 | /// 473 | /// 474 | /// 475 | ///An object that can be used to synchronize access to the collection. 476 | /// 477 | /// 478 | public object SyncRoot 479 | { 480 | get { return syncRoot; } 481 | } 482 | 483 | /// 484 | ///Gets a value indicating whether access to the collection of session-state values is synchronized (thread safe). 485 | /// 486 | /// 487 | ///true if access to the collection is synchronized (thread safe); otherwise, false. 488 | /// 489 | /// 490 | public bool IsSynchronized 491 | { 492 | get { return true; } 493 | } 494 | 495 | /// 496 | ///Gets a value indicating whether the session is read-only. 497 | /// 498 | /// 499 | /// 500 | ///true if the session is read-only; otherwise, false. 501 | /// 502 | /// 503 | bool IHttpSessionState.IsReadOnly 504 | { 505 | get 506 | { 507 | return true; 508 | } 509 | } 510 | 511 | public bool GetIsReadOnly() 512 | { 513 | return IsReadOnly; 514 | } 515 | } 516 | 517 | /// 518 | /// Sets the referer for the request. Uses a fluent interface. 519 | /// 520 | /// 521 | /// 522 | public HttpSimulator SetReferer(Uri referer) 523 | { 524 | if (this.workerRequest != null) 525 | this.workerRequest.SetReferer(referer); 526 | this._referer = referer; 527 | return this; 528 | } 529 | 530 | /// 531 | /// Sets whether it is a request from the local machine. Uses a fluent interface. 532 | /// 533 | /// 534 | /// 535 | public HttpSimulator SetIsLocalRequest(bool isLocalRequest) 536 | { 537 | if (this.workerRequest != null) 538 | this.workerRequest.SetIsLocalRequest(isLocalRequest); 539 | this._isLocalRequest = isLocalRequest; 540 | return this; 541 | } 542 | 543 | /// 544 | /// Sets a form variable. 545 | /// 546 | /// 547 | /// 548 | /// 549 | public HttpSimulator SetFormVariable(string name, string value) 550 | { 551 | //TODO: Change this ordering requirement. 552 | if (this.workerRequest != null) 553 | throw new InvalidOperationException("Cannot set form variables after calling Simulate()."); 554 | 555 | _formVars.Add(name, value); 556 | 557 | return this; 558 | } 559 | 560 | /// 561 | /// Sets a header value. 562 | /// 563 | /// 564 | /// 565 | /// 566 | public HttpSimulator SetHeader(string name, string value) 567 | { 568 | //TODO: Change this ordering requirement. 569 | if (this.workerRequest != null) 570 | throw new InvalidOperationException("Cannot set headers after calling Simulate()."); 571 | 572 | _headers.Add(name, value); 573 | 574 | return this; 575 | } 576 | 577 | /// 578 | /// Sets a browser capabilities. 579 | /// 580 | /// 581 | /// 582 | /// 583 | public HttpSimulator SetBrowser(string name, string value) 584 | { 585 | //TODO: Change this ordering requirement. 586 | if (this.workerRequest != null) 587 | throw new InvalidOperationException("Cannot set browser capabilities after calling Simulate()."); 588 | 589 | _browser.Add(name, value); 590 | 591 | return this; 592 | } 593 | 594 | /// 595 | /// Sets logon user identity. 596 | /// 597 | /// 598 | /// 599 | /// 600 | public HttpSimulator SetIdentity(WindowsIdentity identity) 601 | { 602 | //TODO: Change this ordering requirement. 603 | if (this.workerRequest != null) 604 | throw new InvalidOperationException("Cannot set browser capabilities after calling Simulate()."); 605 | 606 | _identity = identity; 607 | 608 | return this; 609 | } 610 | 611 | private void ParseRequestUrl(Uri url) 612 | { 613 | if (url == null) 614 | return; 615 | this.host = url.Host; 616 | this.port = url.Port; 617 | this.localPath = url.LocalPath; 618 | this._page = StripPrecedingSlashes(RightAfter(url.LocalPath, ApplicationPath)); 619 | this.physicalPath = Path.Combine(this.physicalApplicationPath, this._page.Replace("/", @"\")); 620 | } 621 | 622 | static string RightAfter(string original, string search) 623 | { 624 | if (search.Length > original.Length || search.Length == 0) 625 | return original; 626 | 627 | int searchIndex = original.IndexOf(search, 0, StringComparison.InvariantCultureIgnoreCase); 628 | 629 | if (searchIndex < 0) 630 | return original; 631 | 632 | return original.Substring(original.IndexOf(search) + search.Length); 633 | } 634 | 635 | public string Host 636 | { 637 | get { return this.host; } 638 | } 639 | 640 | private string host; 641 | 642 | public string LocalPath 643 | { 644 | get { return this.localPath; } 645 | } 646 | 647 | private string localPath; 648 | 649 | public int Port 650 | { 651 | get { return this.port; } 652 | } 653 | 654 | private int port; 655 | 656 | /// 657 | /// Portion of the URL after the application. 658 | /// 659 | public string Page 660 | { 661 | get { return this._page; } 662 | } 663 | 664 | private string _page; 665 | 666 | /// 667 | /// The same thing as the IIS Virtual directory. It's 668 | /// what gets returned by Request.ApplicationPath. 669 | /// 670 | public string ApplicationPath 671 | { 672 | get { return this.applicationPath; } 673 | set 674 | { 675 | this.applicationPath = value ?? "/"; 676 | this.applicationPath = NormalizeSlashes(this.applicationPath); 677 | } 678 | } 679 | 680 | private string applicationPath = "/"; 681 | 682 | /// 683 | /// Physical path to the application (used for simulation purposes). 684 | /// 685 | public string PhysicalApplicationPath 686 | { 687 | get { return this.physicalApplicationPath; } 688 | set 689 | { 690 | this.physicalApplicationPath = value ?? defaultPhysicalAppPath; 691 | //strip trailing backslashes. 692 | this.physicalApplicationPath = StripTrailingBackSlashes(this.physicalApplicationPath) + @"\"; 693 | } 694 | } 695 | 696 | private string physicalApplicationPath = defaultPhysicalAppPath; 697 | 698 | /// 699 | /// Physical path to the requested file (used for simulation purposes). 700 | /// 701 | public string PhysicalPath 702 | { 703 | get { return this.physicalPath; } 704 | } 705 | 706 | private string physicalPath = defaultPhysicalAppPath; 707 | 708 | public TextWriter ResponseWriter 709 | { 710 | get { return this.responseWriter; } 711 | set { this.responseWriter = value; } 712 | } 713 | 714 | /// 715 | /// Returns the text from the response to the simulated request. 716 | /// 717 | public string ResponseText 718 | { 719 | get 720 | { 721 | return (builder ?? new StringBuilder()).ToString(); 722 | } 723 | } 724 | 725 | private TextWriter responseWriter; 726 | 727 | /// 728 | /// Returns the text from the response header to the simulated request. 729 | /// 730 | public string ResponseHeaders 731 | { 732 | get 733 | { 734 | return (_responseHeadersBuilder ?? new StringBuilder()).ToString(); 735 | } 736 | } 737 | 738 | private StringBuilder _responseHeadersBuilder; 739 | 740 | public SimulatedHttpRequest WorkerRequest 741 | { 742 | get { return this.workerRequest; } 743 | } 744 | 745 | public HttpContextBase Context { get; private set; } 746 | 747 | private SimulatedHttpRequest workerRequest; 748 | 749 | private static string ExtractQueryStringPart(Uri url) 750 | { 751 | string query = url.Query ?? string.Empty; 752 | if (query.StartsWith("?")) 753 | return query.Substring(1); 754 | return query; 755 | } 756 | 757 | void SetHttpRuntimeInternals() 758 | { 759 | //We cheat by using reflection. 760 | 761 | // get singleton property value 762 | HttpRuntime runtime = ReflectionHelper.GetStaticFieldValue("_theRuntime", typeof(HttpRuntime)); 763 | if (null == runtime) // 764 | return; 765 | // set app path property value 766 | ReflectionHelper.SetPrivateInstanceFieldValue("_appDomainAppPath", runtime, PhysicalApplicationPath); 767 | // set app virtual path property value 768 | string vpathTypeName = "System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; 769 | object virtualPath = ReflectionHelper.Instantiate(vpathTypeName, new Type[] { typeof(string) }, new object[] { ApplicationPath }); 770 | ReflectionHelper.SetPrivateInstanceFieldValue("_appDomainAppVPath", runtime, virtualPath); 771 | 772 | // set codegen dir property value 773 | ReflectionHelper.SetPrivateInstanceFieldValue("_codegenDir", runtime, PhysicalApplicationPath); 774 | 775 | HostingEnvironment environment = GetHostingEnvironment(); 776 | ReflectionHelper.SetPrivateInstanceFieldValue("_appPhysicalPath", environment, PhysicalApplicationPath); 777 | ReflectionHelper.SetPrivateInstanceFieldValue("_appVirtualPath", environment, virtualPath); 778 | ReflectionHelper.SetPrivateInstanceFieldValue("_configMapPath", environment, new ConfigMapPath(this)); 779 | } 780 | 781 | protected static HostingEnvironment GetHostingEnvironment() 782 | { 783 | HostingEnvironment environment; 784 | try 785 | { 786 | environment = new HostingEnvironment(); 787 | } 788 | catch (InvalidOperationException) 789 | { 790 | //Shoot, we need to grab it via reflection. 791 | environment = ReflectionHelper.GetStaticFieldValue("_theHostingEnvironment", typeof(HostingEnvironment)); 792 | } 793 | return environment; 794 | } 795 | 796 | #region --- Text Manipulation Methods for slashes --- 797 | 798 | protected static string NormalizeSlashes(string s) 799 | { 800 | if (String.IsNullOrEmpty(s) || s == "/") 801 | return "/"; 802 | 803 | s = s.Replace(@"\", "/"); 804 | 805 | //Reduce multiple slashes in row to single. 806 | string normalized = Regex.Replace(s, "(/)/+", "$1"); 807 | //Strip left. 808 | normalized = StripPrecedingSlashes(normalized); 809 | //Strip right. 810 | normalized = StripTrailingSlashes(normalized); 811 | return "/" + normalized; 812 | } 813 | 814 | protected static string StripPrecedingSlashes(string s) 815 | { 816 | return Regex.Replace(s, "^/*(.*)", "$1"); 817 | } 818 | 819 | protected static string StripTrailingSlashes(string s) 820 | { 821 | return Regex.Replace(s, "(.*)/*$", "$1", RegexOptions.RightToLeft); 822 | } 823 | 824 | protected static string StripTrailingBackSlashes(string s) 825 | { 826 | if (String.IsNullOrEmpty(s)) 827 | return string.Empty; 828 | return Regex.Replace(s, @"(.*)\\*$", "$1", RegexOptions.RightToLeft); 829 | } 830 | 831 | #endregion --- Text Manipulation Methods for slashes --- 832 | 833 | public class ConfigMapPath : IConfigMapPath 834 | { 835 | private HttpSimulator _requestSimulation; 836 | 837 | public ConfigMapPath(HttpSimulator simulation) 838 | { 839 | _requestSimulation = simulation; 840 | } 841 | 842 | public string GetMachineConfigFilename() 843 | { 844 | return System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile; 845 | } 846 | 847 | public string GetRootWebConfigFilename() 848 | { 849 | return null; 850 | } 851 | 852 | public void GetPathConfigFilename(string siteID, string path, out string directory, out string baseName) 853 | { 854 | directory = _requestSimulation.PhysicalApplicationPath; 855 | baseName = "Web.config"; 856 | } 857 | 858 | public void GetDefaultSiteNameAndID(out string siteName, out string siteID) 859 | { 860 | throw new NotImplementedException(); 861 | } 862 | 863 | public void ResolveSiteArgument(string siteArgument, out string siteName, out string siteID) 864 | { 865 | throw new NotImplementedException(); 866 | } 867 | 868 | public string MapPath(string siteID, string path) 869 | { 870 | string page = StripPrecedingSlashes(RightAfter(path, _requestSimulation.ApplicationPath)); 871 | return Path.Combine(_requestSimulation.PhysicalApplicationPath, page.Replace("/", @"\")); 872 | } 873 | 874 | public string GetAppPathForPath(string siteID, string path) 875 | { 876 | return _requestSimulation.ApplicationPath; 877 | } 878 | } 879 | 880 | /// 881 | ///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 882 | /// 883 | ///2 884 | public void Dispose() 885 | { 886 | if (System.Web.HttpContext.Current != null) 887 | { 888 | System.Web.HttpContext.Current = null; 889 | } 890 | } 891 | } 892 | } 893 | -------------------------------------------------------------------------------- /HttpSimulator/HttpSimulator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8.0.50727 8 | 2.0 9 | {CE9FFE92-9A64-483C-9F11-A27F83C0E14C} 10 | {fae04ec0-301f-11d3-bf4b-00c04f79efbc} 11 | Library 12 | Properties 13 | Http.TestLibrary 14 | HttpSimulator 15 | v4.0 16 | 17 | 18 | 19 | 20 | 2.0 21 | true 22 | 23 | 24 | 25 | 26 | 27 | publish\ 28 | true 29 | Disk 30 | false 31 | Foreground 32 | 7 33 | Days 34 | false 35 | false 36 | true 37 | 0 38 | 1.0.0.%2a 39 | false 40 | false 41 | true 42 | 43 | 44 | true 45 | full 46 | false 47 | bin\ 48 | DEBUG;TRACE 49 | prompt 50 | 4 51 | AllRules.ruleset 52 | 53 | 54 | pdbonly 55 | true 56 | bin\ 57 | TRACE 58 | prompt 59 | 4 60 | AllRules.ruleset 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | False 83 | Microsoft .NET Framework 4 %28x86 and x64%29 84 | true 85 | 86 | 87 | False 88 | .NET Framework 3.5 SP1 Client Profile 89 | false 90 | 91 | 92 | False 93 | .NET Framework 3.5 SP1 94 | false 95 | 96 | 97 | False 98 | Windows Installer 3.1 99 | true 100 | 101 | 102 | 103 | 10.0 104 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 105 | 106 | 107 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /HttpSimulator/IHttpContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Security.Permissions; 4 | using System.Security.Principal; 5 | using System.Web; 6 | using System.Web.Caching; 7 | using System.Web.Profile; 8 | using System.Web.SessionState; 9 | 10 | namespace Http.TestLibrary 11 | { 12 | public interface IHttpContext 13 | { 14 | void AddError(Exception errorInfo); 15 | 16 | void ClearError(); 17 | 18 | object GetSection(string sectionName); 19 | 20 | void RewritePath(string path); 21 | 22 | void RewritePath(string path, bool rebaseClientPath); 23 | 24 | void RewritePath(string filePath, string pathInfo, string queryString); 25 | 26 | void RewritePath(string filePath, string pathInfo, string queryString, bool setClientFilePath); 27 | 28 | // Properties 29 | Exception[] AllErrors { get; } 30 | 31 | HttpApplicationState Application { get; } 32 | 33 | HttpApplication ApplicationInstance { get; set; } 34 | 35 | Cache Cache { get; } 36 | 37 | IHttpHandler CurrentHandler { get; } 38 | 39 | RequestNotification CurrentNotification { get; } 40 | 41 | Exception Error { get; } 42 | 43 | IHttpHandler Handler { get; set; } 44 | 45 | bool IsCustomErrorEnabled { get; } 46 | 47 | bool IsDebuggingEnabled { get; } 48 | 49 | bool IsPostNotification { get; } 50 | 51 | IDictionary Items { get; } 52 | 53 | IHttpHandler PreviousHandler { get; } 54 | 55 | ProfileBase Profile { get; } 56 | 57 | IHttpRequest Request { get; } 58 | 59 | IHttpResponse Response { get; } 60 | 61 | HttpServerUtility Server { get; } 62 | 63 | HttpSessionState Session { get; } 64 | 65 | bool SkipAuthorization { get; [SecurityPermission(SecurityAction.Demand, ControlPrincipal = true)] set; } 66 | 67 | DateTime Timestamp { get; } 68 | 69 | TraceContext Trace { get; } 70 | 71 | IPrincipal User { get; [SecurityPermission(SecurityAction.Demand, ControlPrincipal = true)] set; } 72 | } 73 | } -------------------------------------------------------------------------------- /HttpSimulator/IHttpRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.IO; 4 | using System.Security.Permissions; 5 | using System.Security.Principal; 6 | using System.Text; 7 | using System.Web; 8 | 9 | namespace Http.TestLibrary 10 | { 11 | public interface IHttpRequest 12 | { 13 | byte[] BinaryRead(int count); 14 | 15 | int[] MapImageCoordinates(string imageFieldName); 16 | 17 | string MapPath(string virtualPath); 18 | 19 | string MapPath(string virtualPath, string baseVirtualDir, bool allowCrossAppMapping); 20 | 21 | void SaveAs(string filename, bool includeHeaders); 22 | 23 | void ValidateInput(); 24 | 25 | // Properties 26 | string[] AcceptTypes { get; } 27 | 28 | string AnonymousID { get; } 29 | 30 | string ApplicationPath { get; } 31 | 32 | string AppRelativeCurrentExecutionFilePath { get; } 33 | 34 | HttpBrowserCapabilities Browser { get; set; } 35 | 36 | HttpClientCertificate ClientCertificate { [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)] get; } 37 | 38 | Encoding ContentEncoding { get; set; } 39 | 40 | int ContentLength { get; } 41 | 42 | string ContentType { get; set; } 43 | 44 | HttpCookieCollection Cookies { get; } 45 | 46 | string CurrentExecutionFilePath { get; } 47 | 48 | string FilePath { get; } 49 | 50 | HttpFileCollection Files { get; } 51 | 52 | Stream Filter { get; set; } 53 | 54 | NameValueCollection Form { get; } 55 | 56 | NameValueCollection Headers { get; } 57 | 58 | string HttpMethod { get; } 59 | 60 | Stream InputStream { get; } 61 | 62 | bool IsAuthenticated { get; } 63 | 64 | bool IsLocal { get; } 65 | 66 | bool IsSecureConnection { get; } 67 | 68 | string this [string key] { get; } 69 | 70 | WindowsIdentity LogonUserIdentity { [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)] get; } 71 | 72 | NameValueCollection Params { get; } 73 | 74 | string Path { get; } 75 | 76 | string PathInfo { get; } 77 | 78 | string PhysicalApplicationPath { get; } 79 | 80 | string PhysicalPath { get; } 81 | 82 | NameValueCollection QueryString { get; } 83 | 84 | string RawUrl { get; } 85 | 86 | string RequestType { get; set; } 87 | 88 | NameValueCollection ServerVariables { get; } 89 | 90 | int TotalBytes { get; } 91 | 92 | Uri Url { get; } 93 | 94 | Uri UrlReferrer { get; } 95 | 96 | string UserAgent { get; } 97 | 98 | string UserHostAddress { get; } 99 | 100 | string UserHostName { get; } 101 | 102 | string[] UserLanguages { get; } 103 | } 104 | } -------------------------------------------------------------------------------- /HttpSimulator/IHttpResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Specialized; 4 | using System.IO; 5 | using System.Security.Permissions; 6 | using System.Text; 7 | using System.Web; 8 | using System.Web.Caching; 9 | 10 | namespace Http.TestLibrary 11 | { 12 | public interface IHttpResponse 13 | { 14 | void AddCacheDependency(params CacheDependency[] dependencies); 15 | 16 | void AddCacheItemDependencies(string[] cacheKeys); 17 | 18 | void AddCacheItemDependencies(ArrayList cacheKeys); 19 | 20 | void AddCacheItemDependency(string cacheKey); 21 | 22 | void AddFileDependencies(ArrayList filenames); 23 | 24 | void AddFileDependencies(string[] filenames); 25 | 26 | void AddFileDependency(string filename); 27 | 28 | void AddHeader(string name, string value); 29 | 30 | void AppendCookie(HttpCookie cookie); 31 | 32 | void AppendHeader(string name, string value); 33 | 34 | [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)] 35 | void AppendToLog(string param); 36 | 37 | string ApplyAppPathModifier(string virtualPath); 38 | 39 | void BinaryWrite(byte[] buffer); 40 | 41 | void Clear(); 42 | 43 | void ClearContent(); 44 | 45 | void ClearHeaders(); 46 | 47 | void Close(); 48 | 49 | void DisableKernelCache(); 50 | 51 | void End(); 52 | 53 | void Flush(); 54 | 55 | void Pics(string value); 56 | 57 | void Redirect(string url); 58 | 59 | void Redirect(string url, bool endResponse); 60 | 61 | void SetCookie(HttpCookie cookie); 62 | 63 | void TransmitFile(string filename); 64 | 65 | void TransmitFile(string filename, long offset, long length); 66 | 67 | void Write(char ch); 68 | 69 | void Write(object obj); 70 | 71 | void Write(string s); 72 | 73 | void Write(char[] buffer, int index, int count); 74 | 75 | void WriteFile(string filename); 76 | 77 | void WriteFile(string filename, bool readIntoMemory); 78 | 79 | [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] 80 | void WriteFile(IntPtr fileHandle, long offset, long size); 81 | 82 | void WriteFile(string filename, long offset, long size); 83 | 84 | void WriteSubstitution(HttpResponseSubstitutionCallback callback); 85 | 86 | // Properties 87 | bool Buffer { get; set; } 88 | 89 | bool BufferOutput { get; set; } 90 | 91 | HttpCachePolicy Cache { get; } 92 | 93 | string CacheControl { get; set; } 94 | 95 | string Charset { get; set; } 96 | 97 | Encoding ContentEncoding { get; set; } 98 | 99 | string ContentType { get; set; } 100 | 101 | HttpCookieCollection Cookies { get; } 102 | 103 | int Expires { get; set; } 104 | 105 | DateTime ExpiresAbsolute { get; set; } 106 | 107 | Stream Filter { get; set; } 108 | 109 | Encoding HeaderEncoding { get; set; } 110 | 111 | NameValueCollection Headers { get; } 112 | 113 | bool IsClientConnected { get; } 114 | 115 | bool IsRequestBeingRedirected { get; } 116 | 117 | TextWriter Output { get; } 118 | 119 | Stream OutputStream { get; } 120 | 121 | string RedirectLocation { get; set; } 122 | 123 | string Status { get; set; } 124 | 125 | int StatusCode { get; set; } 126 | 127 | string StatusDescription { get; set; } 128 | 129 | int SubStatusCode { get; set; } 130 | 131 | bool SuppressContent { get; set; } 132 | } 133 | } -------------------------------------------------------------------------------- /HttpSimulator/IHttpServerUtility.cs: -------------------------------------------------------------------------------- 1 | namespace Http.TestLibrary 2 | { 3 | public class IHttpServerUtility 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /HttpSimulator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("HttpSimulator")] 9 | [assembly: AssemblyDescription("A simple library used for simulating http context during unit or integration testing")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("HttpSimulator")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3d5900ae-111a-45be-96b3-d9e4606ca793")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("2.4.0.0")] 35 | [assembly: AssemblyFileVersion("2.4.0.0")] 36 | -------------------------------------------------------------------------------- /HttpSimulator/ReflectionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Http.TestLibrary 5 | { 6 | /// 7 | /// Helper class to simplify common reflection tasks. 8 | /// 9 | public sealed class ReflectionHelper 10 | { 11 | private ReflectionHelper() 12 | { 13 | } 14 | 15 | /// 16 | /// Returns the value of the private member specified. 17 | /// 18 | /// Name of the member. 19 | /// /// Type of the member. 20 | public static T GetStaticFieldValue(string fieldName, Type type) 21 | { 22 | FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static); 23 | if (field != null) 24 | { 25 | return (T)field.GetValue(type); 26 | } 27 | return default(T); 28 | } 29 | 30 | /// 31 | /// Returns the value of the private member specified. 32 | /// 33 | /// Name of the member. 34 | /// 35 | public static T GetStaticFieldValue(string fieldName, string typeName) 36 | { 37 | Type type = Type.GetType(typeName, true); 38 | FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static); 39 | if (field != null) 40 | { 41 | return (T)field.GetValue(type); 42 | } 43 | return default(T); 44 | } 45 | 46 | /// 47 | /// Sets the value of the private static member. 48 | /// 49 | /// 50 | /// 51 | /// 52 | public static void SetStaticFieldValue(string fieldName, Type type, T value) 53 | { 54 | FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static); 55 | if (field == null) 56 | throw new ArgumentException(string.Format("Could not find the private instance field '{0}'", fieldName)); 57 | 58 | field.SetValue(null, value); 59 | } 60 | 61 | /// 62 | /// Sets the value of the private static member. 63 | /// 64 | /// 65 | /// 66 | /// 67 | public static void SetStaticFieldValue(string fieldName, string typeName, T value) 68 | { 69 | Type type = Type.GetType(typeName, true); 70 | FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static); 71 | if (field == null) 72 | throw new ArgumentException(string.Format("Could not find the private instance field '{0}'", fieldName)); 73 | 74 | field.SetValue(null, value); 75 | } 76 | 77 | /// 78 | /// Returns the value of the private member specified. 79 | /// 80 | /// Name of the member. 81 | /// The object that contains the member. 82 | public static T GetPrivateInstanceFieldValue(string fieldName, object source) 83 | { 84 | FieldInfo field = source.GetType().GetField(fieldName, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance); 85 | if (field != null) 86 | { 87 | return (T)field.GetValue(source); 88 | } 89 | return default(T); 90 | } 91 | 92 | /// 93 | /// Returns the value of the private member specified. 94 | /// 95 | /// Name of the member. 96 | /// The object that contains the member. 97 | /// The value to set the member to. 98 | public static void SetPrivateInstanceFieldValue(string memberName, object source, object value) 99 | { 100 | FieldInfo field = source.GetType().GetField(memberName, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance); 101 | if (field == null) 102 | throw new ArgumentException(string.Format("Could not find the private instance field '{0}'", memberName)); 103 | 104 | field.SetValue(source, value); 105 | } 106 | 107 | public static object Instantiate(string typeName) 108 | { 109 | return Instantiate(typeName, null, null); 110 | } 111 | 112 | public static object Instantiate(string typeName, Type[] constructorArgumentTypes, params object[] constructorParameterValues) 113 | { 114 | return Instantiate(Type.GetType(typeName, true), constructorArgumentTypes, constructorParameterValues); 115 | } 116 | 117 | public static object Instantiate(Type type, Type[] constructorArgumentTypes, params object[] constructorParameterValues) 118 | { 119 | ConstructorInfo constructor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, constructorArgumentTypes, null); 120 | return constructor.Invoke(constructorParameterValues); 121 | } 122 | 123 | /// 124 | /// Invokes a non-public static method. 125 | /// 126 | /// 127 | /// 128 | /// 129 | /// 130 | /// 131 | public static TReturn InvokeNonPublicMethod(Type type, string methodName, params object[] parameters) 132 | { 133 | Type[] paramTypes = Array.ConvertAll(parameters, new Converter(delegate(object o) 134 | { 135 | return o.GetType(); 136 | })); 137 | 138 | MethodInfo method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static, null, paramTypes, null); 139 | if (method == null) 140 | throw new ArgumentException(string.Format("Could not find a method with the name '{0}'", methodName), "method"); 141 | 142 | return (TReturn)method.Invoke(null, parameters); 143 | } 144 | 145 | public static TReturn InvokeNonPublicMethod(object source, string methodName, params object[] parameters) 146 | { 147 | Type[] paramTypes = Array.ConvertAll(parameters, new Converter(delegate(object o) 148 | { 149 | return o.GetType(); 150 | })); 151 | 152 | MethodInfo method = source.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, paramTypes, null); 153 | if (method == null) 154 | throw new ArgumentException(string.Format("Could not find a method with the name '{0}'", methodName), "method"); 155 | 156 | return (TReturn)method.Invoke(source, parameters); 157 | } 158 | 159 | public static TReturn InvokeProperty(object source, string propertyName) 160 | { 161 | PropertyInfo propertyInfo = source.GetType().GetProperty(propertyName); 162 | if (propertyInfo == null) 163 | throw new ArgumentException(string.Format("Could not find a propertyName with the name '{0}'", propertyName), "propertyName"); 164 | 165 | return (TReturn)propertyInfo.GetValue(source, null); 166 | } 167 | 168 | public static TReturn InvokeNonPublicProperty(object source, string propertyName) 169 | { 170 | PropertyInfo propertyInfo = source.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance, null, typeof(TReturn), new Type[0], null); 171 | if (propertyInfo == null) 172 | throw new ArgumentException(string.Format("Could not find a propertyName with the name '{0}'", propertyName), "propertyName"); 173 | 174 | return (TReturn)propertyInfo.GetValue(source, null); 175 | } 176 | 177 | public static object InvokeNonPublicProperty(object source, string propertyName) 178 | { 179 | PropertyInfo propertyInfo = source.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance); 180 | if (propertyInfo == null) 181 | throw new ArgumentException(string.Format("Could not find a propertyName with the name '{0}'", propertyName), "propertyName"); 182 | 183 | return propertyInfo.GetValue(source, null); 184 | } 185 | } 186 | } -------------------------------------------------------------------------------- /HttpSimulator/SimulatedHttpRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Specialized; 4 | using System.IO; 5 | using System.Security.Principal; 6 | using System.Text; 7 | using System.Web; 8 | using System.Web.Hosting; 9 | 10 | namespace Http.TestLibrary 11 | { 12 | /// 13 | /// Used to simulate an HttpRequest. 14 | /// 15 | public class SimulatedHttpRequest : SimpleWorkerRequest 16 | { 17 | Uri _referer; 18 | string _host; 19 | string _verb; 20 | int _port; 21 | string _physicalFilePath; 22 | bool _isLocalRequest; 23 | StringBuilder _responseHeaders; 24 | 25 | /// 26 | /// Creates a new instance. 27 | /// 28 | /// App virtual dir. 29 | /// Physical Path to the app. 30 | /// Physical Path to the file. 31 | /// The Part of the URL after the application. 32 | /// Query. 33 | /// Output. 34 | /// Host. 35 | /// Port to request. 36 | /// The HTTP Verb to use. 37 | /// 38 | public SimulatedHttpRequest(string applicationPath, string physicalAppPath, string physicalFilePath, string page, string query, TextWriter output, string host, int port, string verb, Uri url, StringBuilder responseHeadersOutput) 39 | : base(applicationPath, physicalAppPath, page, query, output) 40 | { 41 | if (host == null) 42 | throw new ArgumentNullException("host", "Host cannot be null."); 43 | 44 | if (host.Length == 0) 45 | throw new ArgumentException("Host cannot be empty.", "host"); 46 | 47 | if (applicationPath == null) 48 | throw new ArgumentNullException("applicationPath", "Can't create a request with a null application path. Try empty string."); 49 | 50 | _host = host; 51 | _verb = verb; 52 | _port = port; 53 | _physicalFilePath = physicalFilePath; 54 | this.Uri = url; 55 | _responseHeaders = responseHeadersOutput; 56 | } 57 | 58 | internal void SetReferer(Uri referer) 59 | { 60 | _referer = referer; 61 | } 62 | 63 | internal void SetIsLocalRequest(bool isLocalRequest) 64 | { 65 | _isLocalRequest = isLocalRequest; 66 | } 67 | 68 | /// 69 | /// Returns the specified member of the request header. 70 | /// 71 | /// 72 | /// The HTTP verb returned in the request 73 | /// header. 74 | /// 75 | public override string GetHttpVerbName() 76 | { 77 | return _verb; 78 | } 79 | 80 | /// 81 | /// Gets the name of the server. 82 | /// 83 | /// 84 | public override string GetServerName() 85 | { 86 | return _host; 87 | } 88 | 89 | public override int GetLocalPort() 90 | { 91 | return this._port; 92 | } 93 | 94 | /// 95 | /// Gets the headers. 96 | /// 97 | /// The headers. 98 | public NameValueCollection Headers 99 | { 100 | get 101 | { 102 | return this.headers; 103 | } 104 | } 105 | 106 | private NameValueCollection headers = new NameValueCollection(); 107 | 108 | /// 109 | /// Gets the Form. 110 | /// 111 | /// The Form. 112 | public NameValueCollection Form 113 | { 114 | get 115 | { 116 | return formVariables; 117 | } 118 | } 119 | 120 | public Uri Uri { get; private set; } 121 | 122 | private NameValueCollection formVariables = new NameValueCollection(); 123 | 124 | public HttpBrowserCapabilities Browser 125 | { 126 | get 127 | { 128 | return browser; 129 | } 130 | } 131 | 132 | private HttpBrowserCapabilities browser = new HttpBrowserCapabilities{ Capabilities = new Dictionary() }; 133 | 134 | internal void SetIdentity(WindowsIdentity identity) 135 | { 136 | _identity = identity; 137 | } 138 | 139 | private WindowsIdentity _identity = null; 140 | 141 | /// 142 | /// Get all nonstandard HTTP header name-value pairs. 143 | /// 144 | /// An array of header name-value pairs. 145 | public override string[][] GetUnknownRequestHeaders() 146 | { 147 | if (this.headers == null || this.headers.Count == 0) 148 | { 149 | return null; 150 | } 151 | string[][] headersArray = new string[this.headers.Count][]; 152 | for (int i = 0; i < this.headers.Count; i++) 153 | { 154 | headersArray[i] = new string[2]; 155 | headersArray[i][0] = this.headers.Keys[i]; 156 | headersArray[i][1] = this.headers[i]; 157 | } 158 | return headersArray; 159 | } 160 | 161 | public override string GetKnownRequestHeader(int index) 162 | { 163 | switch (index) { 164 | case HttpWorkerRequest.HeaderReferer: 165 | return _referer == null ? string.Empty : _referer.ToString(); 166 | case HttpWorkerRequest.HeaderContentType: 167 | string ct = headers["Content-Type"] ?? (_verb == "POST" ? "application/x-www-form-urlencoded" : null); 168 | if (ct != null) 169 | return ct; 170 | break; 171 | case HttpWorkerRequest.HeaderAcceptLanguage: 172 | return headers["Accept-Language"]; 173 | case HttpWorkerRequest.HeaderUserAgent: 174 | return headers["User-Agent"]; 175 | case HttpWorkerRequest.HeaderCookie: 176 | return headers["Cookie"]; 177 | } 178 | return base.GetKnownRequestHeader(index); 179 | } 180 | 181 | public override string GetServerVariable(string name) 182 | { 183 | switch (name) { 184 | case "HTTP_USER_AGENT": 185 | return GetKnownRequestHeader(HttpWorkerRequest.HeaderUserAgent); 186 | case "AUTH_TYPE": 187 | return _identity != null ? _identity.AuthenticationType : base.GetServerVariable(name); 188 | case "LOGON_USER": 189 | return _identity != null ? _identity.Name : base.GetServerVariable(name); 190 | } 191 | return base.GetServerVariable(name); 192 | } 193 | 194 | /// 195 | /// Returns the virtual path to the currently executing 196 | /// server application. 197 | /// 198 | /// 199 | /// The virtual path of the current application. 200 | /// 201 | public override string GetAppPath() 202 | { 203 | string appPath = base.GetAppPath(); 204 | return appPath; 205 | } 206 | 207 | public override string GetAppPathTranslated() 208 | { 209 | string path = base.GetAppPathTranslated(); 210 | return path; 211 | } 212 | 213 | public override string GetUriPath() 214 | { 215 | string uriPath = base.GetUriPath(); 216 | return uriPath; 217 | } 218 | 219 | public override string GetFilePathTranslated() 220 | { 221 | return _physicalFilePath; 222 | } 223 | 224 | /// 225 | /// Reads request data from the client (when not preloaded). 226 | /// 227 | /// The number of bytes read. 228 | public override byte[] GetPreloadedEntityBody() 229 | { 230 | string formText = string.Empty; 231 | 232 | foreach (string key in this.formVariables.Keys) 233 | { 234 | formText += string.Format("{0}={1}&", key, this.formVariables[key]); 235 | } 236 | 237 | return Encoding.UTF8.GetBytes(formText); 238 | } 239 | 240 | /// 241 | /// Returns a value indicating whether all request data 242 | /// is available and no further reads from the client are required. 243 | /// 244 | /// 245 | /// if all request data is available; otherwise, 246 | /// . 247 | /// 248 | public override bool IsEntireEntityBodyIsPreloaded() 249 | { 250 | return true; 251 | } 252 | 253 | //GetLogonUserIdentity 254 | public override IntPtr GetUserToken() 255 | { 256 | return _identity?.Token ?? base.GetUserToken(); 257 | } 258 | 259 | public override string GetRemoteAddress() 260 | { 261 | return _isLocalRequest ? "127.0.0.1" : ""; 262 | } 263 | 264 | public override void SendKnownResponseHeader(int index, string value) 265 | { 266 | _responseHeaders.Append(GetKnownResponseHeaderName(index)); 267 | _responseHeaders.Append(": "); 268 | _responseHeaders.Append(value); 269 | _responseHeaders.Append("\r\n"); 270 | } 271 | 272 | public override void SendUnknownResponseHeader(string name, string value) 273 | { 274 | _responseHeaders.Append(name); 275 | _responseHeaders.Append(": "); 276 | _responseHeaders.Append(value); 277 | _responseHeaders.Append("\r\n"); 278 | } 279 | 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU General Public License 2 | 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies of this license 9 | document, but changing it is not allowed. 10 | 11 | Preamble 12 | 13 | The licenses for most software are designed to take away your freedom to 14 | share and change it. By contrast, the GNU General Public License is intended 15 | to guarantee your freedom to share and change free software--to make sure 16 | the software is free for all its users. This General Public License applies 17 | to most of the Free Software Foundation's software and to any other program 18 | whose authors commit to using it. (Some other Free Software Foundation 19 | software is covered by the GNU Library General Public License instead.) You 20 | can apply it to your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not price. Our 23 | General Public Licenses are designed to make sure that you have the freedom 24 | to distribute copies of free software (and charge for this service if you 25 | wish), that you receive source code or can get it if you want it, that you 26 | can change the software or use pieces of it in new free programs; and that 27 | you know you can do these things. 28 | 29 | To protect your rights, we need to make restrictions that forbid anyone to 30 | deny you these rights or to ask you to surrender the rights. These 31 | restrictions translate to certain responsibilities for you if you distribute 32 | copies of the software, or if you modify it. 33 | 34 | For example, if you distribute copies of such a program, whether gratis or 35 | for a fee, you must give the recipients all the rights that you have. You 36 | must make sure that they, too, receive or can get the source code. And you 37 | must show them these terms so they know their rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and (2) 40 | offer you this license which gives you legal permission to copy, distribute 41 | and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain that 44 | everyone understands that there is no warranty for this free software. If 45 | the software is modified by someone else and passed on, we want its 46 | recipients to know that what they have is not the original, so that any 47 | problems introduced by others will not reflect on the original authors' 48 | reputations. 49 | 50 | Finally, any free program is threatened constantly by software patents. We 51 | wish to avoid the danger that redistributors of a free program will 52 | individually obtain patent licenses, in effect making the program 53 | proprietary. To prevent this, we have made it clear that any patent must be 54 | licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and modification 57 | follow. 58 | 59 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 60 | 61 | 0. This License applies to any program or other work which contains a notice 62 | placed by the copyright holder saying it may be distributed under the 63 | terms of this General Public License. The "Program", below, refers to any 64 | such program or work, and a "work based on the Program" means either the 65 | Program or any derivative work under copyright law: that is to say, a 66 | work containing the Program or a portion of it, either verbatim or with 67 | modifications and/or translated into another language. (Hereinafter, 68 | translation is included without limitation in the term "modification".) 69 | Each licensee is addressed as "you". 70 | 71 | Activities other than copying, distribution and modification are not 72 | covered by this License; they are outside its scope. The act of running 73 | the Program is not restricted, and the output from the Program is covered 74 | only if its contents constitute a work based on the Program (independent 75 | of having been made by running the Program). Whether that is true depends 76 | on what the Program does. 77 | 78 | 1. You may copy and distribute verbatim copies of the Program's source code 79 | as you receive it, in any medium, provided that you conspicuously and 80 | appropriately publish on each copy an appropriate copyright notice and 81 | disclaimer of warranty; keep intact all the notices that refer to this 82 | License and to the absence of any warranty; and give any other recipients 83 | of the Program a copy of this License along with the Program. 84 | 85 | You may charge a fee for the physical act of transferring a copy, and you 86 | may at your option offer warranty protection in exchange for a fee. 87 | 88 | 2. You may modify your copy or copies of the Program or any portion of it, 89 | thus forming a work based on the Program, and copy and distribute such 90 | modifications or work under the terms of Section 1 above, provided that 91 | you also meet all of these conditions: 92 | 93 | * a) You must cause the modified files to carry prominent notices stating 94 | that you changed the files and the date of any change. 95 | 96 | * b) You must cause any work that you distribute or publish, that in 97 | whole or in part contains or is derived from the Program or any part 98 | thereof, to be licensed as a whole at no charge to all third parties 99 | under the terms of this License. 100 | 101 | * c) If the modified program normally reads commands interactively when 102 | run, you must cause it, when started running for such interactive 103 | use in the most ordinary way, to print or display an announcement 104 | including an appropriate copyright notice and a notice that there is 105 | no warranty (or else, saying that you provide a warranty) and that 106 | users may redistribute the program under these conditions, and 107 | telling the user how to view a copy of this License. (Exception: if 108 | the Program itself is interactive but does not normally print such 109 | an announcement, your work based on the Program is not required to 110 | print an announcement.) 111 | 112 | These requirements apply to the modified work as a whole. If identifiable 113 | sections of that work are not derived from the Program, and can be 114 | reasonably considered independent and separate works in themselves, then 115 | this License, and its terms, do not apply to those sections when you 116 | distribute them as separate works. But when you distribute the same 117 | sections as part of a whole which is a work based on the Program, the 118 | distribution of the whole must be on the terms of this License, whose 119 | permissions for other licensees extend to the entire whole, and thus to 120 | each and every part regardless of who wrote it. 121 | 122 | Thus, it is not the intent of this section to claim rights or contest 123 | your rights to work written entirely by you; rather, the intent is to 124 | exercise the right to control the distribution of derivative or 125 | collective works based on the Program. 126 | 127 | In addition, mere aggregation of another work not based on the Program 128 | with the Program (or with a work based on the Program) on a volume of a 129 | storage or distribution medium does not bring the other work under the 130 | scope of this License. 131 | 132 | 3. You may copy and distribute the Program (or a work based on it, under 133 | Section 2) in object code or executable form under the terms of Sections 134 | 1 and 2 above provided that you also do one of the following: 135 | 136 | * a) Accompany it with the complete corresponding machine-readable source 137 | code, which must be distributed under the terms of Sections 1 and 2 138 | above on a medium customarily used for software interchange; or, 139 | 140 | * b) Accompany it with a written offer, valid for at least three years, 141 | to give any third party, for a charge no more than your cost of 142 | physically performing source distribution, a complete machine- 143 | readable copy of the corresponding source code, to be distributed 144 | under the terms of Sections 1 and 2 above on a medium customarily 145 | used for software interchange; or, 146 | 147 | * c) Accompany it with the information you received as to the offer to 148 | distribute corresponding source code. (This alternative is allowed 149 | only for noncommercial distribution and only if you received the 150 | program in object code or executable form with such an offer, in 151 | accord with Subsection b above.) 152 | 153 | The source code for a work means the preferred form of the work for 154 | making modifications to it. For an executable work, complete source code 155 | means all the source code for all modules it contains, plus any 156 | associated interface definition files, plus the scripts used to control 157 | compilation and installation of the executable. However, as a special 158 | exception, the source code distributed need not include anything that is 159 | normally distributed (in either source or binary form) with the major 160 | components (compiler, kernel, and so on) of the operating system on which 161 | the executable runs, unless that component itself accompanies the 162 | executable. 163 | 164 | If distribution of executable or object code is made by offering access 165 | to copy from a designated place, then offering equivalent access to copy 166 | the source code from the same place counts as distribution of the source 167 | code, even though third parties are not compelled to copy the source 168 | along with the object code. 169 | 170 | 4. You may not copy, modify, sublicense, or distribute the Program except as 171 | expressly provided under this License. Any attempt otherwise to copy, 172 | modify, sublicense or distribute the Program is void, and will 173 | automatically terminate your rights under this License. However, parties 174 | who have received copies, or rights, from you under this License will not 175 | have their licenses terminated so long as such parties remain in full 176 | compliance. 177 | 178 | 5. You are not required to accept this License, since you have not signed 179 | it. However, nothing else grants you permission to modify or distribute 180 | the Program or its derivative works. These actions are prohibited by law 181 | if you do not accept this License. Therefore, by modifying or 182 | distributing the Program (or any work based on the Program), you 183 | indicate your acceptance of this License to do so, and all its terms and 184 | conditions for copying, distributing or modifying the Program or works 185 | based on it. 186 | 187 | 6. Each time you redistribute the Program (or any work based on the 188 | Program), the recipient automatically receives a license from the 189 | original licensor to copy, distribute or modify the Program subject to 190 | these terms and conditions. You may not impose any further restrictions 191 | on the recipients' exercise of the rights granted herein. You are not 192 | responsible for enforcing compliance by third parties to this License. 193 | 194 | 7. If, as a consequence of a court judgment or allegation of patent 195 | infringement or for any other reason (not limited to patent issues), 196 | conditions are imposed on you (whether by court order, agreement or 197 | otherwise) that contradict the conditions of this License, they do not 198 | excuse you from the conditions of this License. If you cannot distribute 199 | so as to satisfy simultaneously your obligations under this License and 200 | any other pertinent obligations, then as a consequence you may not 201 | distribute the Program at all. For example, if a patent license would 202 | not permit royalty-free redistribution of the Program by all those who 203 | receive copies directly or indirectly through you, then the only way you 204 | could satisfy both it and this License would be to refrain entirely from 205 | distribution of the Program. 206 | 207 | If any portion of this section is held invalid or unenforceable under any 208 | particular circumstance, the balance of the section is intended to apply 209 | and the section as a whole is intended to apply in other circumstances. 210 | 211 | It is not the purpose of this section to induce you to infringe any 212 | patents or other property right claims or to contest validity of any 213 | such claims; this section has the sole purpose of protecting the 214 | integrity of the free software distribution system, which is implemented 215 | by public license practices. Many people have made generous contributions 216 | to the wide range of software distributed through that system in 217 | reliance on consistent application of that system; it is up to the 218 | author/donor to decide if he or she is willing to distribute software 219 | through any other system and a licensee cannot impose that choice. 220 | 221 | This section is intended to make thoroughly clear what is believed to be 222 | a consequence of the rest of this License. 223 | 224 | 8. If the distribution and/or use of the Program is restricted in certain 225 | countries either by patents or by copyrighted interfaces, the original 226 | copyright holder who places the Program under this License may add an 227 | explicit geographical distribution limitation excluding those countries, 228 | so that distribution is permitted only in or among countries not thus 229 | excluded. In such case, this License incorporates the limitation as if 230 | written in the body of this License. 231 | 232 | 9. The Free Software Foundation may publish revised and/or new versions of 233 | the General Public License from time to time. Such new versions will be 234 | similar in spirit to the present version, but may differ in detail to 235 | address new problems or concerns. 236 | 237 | Each version is given a distinguishing version number. If the Program 238 | specifies a version number of this License which applies to it and "any 239 | later version", you have the option of following the terms and 240 | conditions either of that version or of any later version published by 241 | the Free Software Foundation. If the Program does not specify a version 242 | number of this License, you may choose any version ever published by the 243 | Free Software Foundation. 244 | 245 | 10. If you wish to incorporate parts of the Program into other free programs 246 | whose distribution conditions are different, write to the author to ask 247 | for permission. For software which is copyrighted by the Free Software 248 | Foundation, write to the Free Software Foundation; we sometimes make 249 | exceptions for this. Our decision will be guided by the two goals of 250 | preserving the free status of all derivatives of our free software and 251 | of promoting the sharing and reuse of software generally. 252 | 253 | NO WARRANTY 254 | 255 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 256 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 257 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 258 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 259 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 260 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 261 | ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH 262 | YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL 263 | NECESSARY SERVICING, REPAIR OR CORRECTION. 264 | 265 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 266 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 267 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 268 | DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 269 | DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 270 | (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 271 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 272 | THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 273 | OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 274 | 275 | END OF TERMS AND CONDITIONS 276 | 277 | How to Apply These Terms to Your New Programs 278 | 279 | If you develop a new program, and you want it to be of the greatest 280 | possible use to the public, the best way to achieve this is to make it free 281 | software which everyone can redistribute and change under these terms. 282 | 283 | To do so, attach the following notices to the program. It is safest to 284 | attach them to the start of each source file to most effectively convey the 285 | exclusion of warranty; and each file should have at least the "copyright" 286 | line and a pointer to where the full notice is found. 287 | 288 | one line to give the program's name and an idea of what it does. 289 | Copyright (C) yyyy name of author 290 | 291 | This program is free software; you can redistribute it and/or modify it 292 | under the terms of the GNU General Public License as published by the Free 293 | Software Foundation; either version 2 of the License, or (at your option) 294 | any later version. 295 | 296 | This program is distributed in the hope that it will be useful, but WITHOUT 297 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 298 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 299 | more details. 300 | 301 | You should have received a copy of the GNU General Public License along with 302 | this program; if not, write to the Free Software Foundation, Inc., 59 303 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. 304 | 305 | Also add information on how to contact you by electronic and paper mail. 306 | 307 | If the program is interactive, make it output a short notice like this when 308 | it starts in an interactive mode: 309 | 310 | Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 311 | with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free 312 | software, and you are welcome to redistribute it under certain conditions; 313 | type 'show c' for details. 314 | 315 | The hypothetical commands 'show w' and 'show c' should show the appropriate 316 | parts of the General Public License. Of course, the commands you use may be 317 | called something other than 'show w' and 'show c'; they could even be 318 | mouse-clicks or menu items--whatever suits your program. 319 | 320 | You should also get your employer (if you work as a programmer) or your 321 | school, if any, to sign a "copyright disclaimer" for the program, if 322 | necessary. Here is a sample; alter the names: 323 | 324 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 325 | 'Gnomovision' (which makes passes at compilers) written by James Hacker. 326 | 327 | signature of Ty Coon, 1 April 1989 328 | Ty Coon, President of Vice 329 | 330 | This General Public License does not permit incorporating your program into 331 | proprietary programs. If your program is a subroutine library, you may 332 | consider it more useful to permit linking proprietary applications with the 333 | library. If this is what you want to do, use the GNU Library General Public 334 | License instead of this License. 335 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | httpcontext-simulator [![Build Status](https://img.shields.io/travis/ferronrsmith/httpcontext-simulator.svg)](https://travis-ci.org/ferronrsmith/httpcontext-simulator) [![HttpSimulator](https://img.shields.io/nuget/v/HttpSimulator.svg)](https://www.nuget.org/packages/HttpSimulator) 2 | ===================== 3 | 4 | A simple library used for simulating http context during unit or integration testing 5 | 6 | Can simulate: 7 | - form get with querystring 8 | - form post 9 | - session 10 | - user agent 11 | - cookie 12 | - browser capabilities 13 | - logon user identity 14 | - response headers 15 | 16 | ### Introduction 17 | The following shows how to use HttpSimulator?. 18 | 19 | ```csharp 20 | using System; 21 | using System.Collections.Specialized; 22 | 23 | /** 24 | * 25 | * The following spike was created to show an example of how to use the HttpSimuator library 26 | * 27 | * 28 | */ 29 | using System.Web; 30 | using NUnit.Framework; 31 | using Http.TestLibrary; 32 | 33 | namespace UsingHttpSimulator 34 | { 35 | [TestFixture] 36 | public class UsingHttpSimulatorTest 37 | { 38 | /// 39 | /// Determines whether this instance [can get set session]. 40 | /// 41 | [Test] 42 | public void CanGetSetSession() 43 | { 44 | using (new HttpSimulator("/", @"c:\inetpub\").SimulateRequest()) 45 | { 46 | HttpContext.Current.Session["Test"] = "Success"; 47 | Assert.AreEqual("Success", HttpContext.Current.Session["Test"]); 48 | } 49 | } 50 | 51 | /// 52 | /// Determines whether this instance [can simulate form post]. 53 | /// 54 | [Test] 55 | public void CanSimulateFormPost() 56 | { 57 | using (HttpSimulator simulator = new HttpSimulator()) 58 | { 59 | NameValueCollection form = new NameValueCollection(); 60 | form.Add("Test1", "Value1"); 61 | form.Add("Test2", "Value2"); 62 | simulator.SimulateRequest(new Uri("http://localhost/Test.aspx"), form); 63 | 64 | Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]); 65 | Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]); 66 | } 67 | 68 | using (HttpSimulator simulator = new HttpSimulator()) 69 | { 70 | simulator.SetFormVariable("Test1", "Value1") 71 | .SetFormVariable("Test2", "Value2") 72 | .SimulateRequest(new Uri("http://localhost/Test.aspx")); 73 | 74 | Assert.AreEqual("Value1", HttpContext.Current.Request.Form["Test1"]); 75 | Assert.AreEqual("Value2", HttpContext.Current.Request.Form["Test2"]); 76 | } 77 | } 78 | } 79 | } 80 | ``` 81 | --------------------------------------------------------------------------------