├── .gitignore
├── .scannerwork
└── .sonar_lock
├── .travis.yml
├── Dockerfile
├── HTTPServer
├── HTTPClient
│ ├── App.config
│ ├── HttpClient.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── bin
│ │ └── Debug
│ │ └── HttpClient.exe.config
├── HTTPServer.sln
├── HTTPServer
│ ├── App.config
│ ├── ConsoleLogger.cs
│ ├── ExampleServer.cs
│ ├── HttpServer.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
├── HTTPServerLib.UnitTest
│ ├── HttpServerLib.UnitTest.csproj
│ ├── HttpServerTest.cs
│ ├── HttpServiceTest.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
├── HTTPServerLib
│ ├── ActionResult.cs
│ ├── BaseHeader.cs
│ ├── HeadersHelper.cs
│ ├── HttpRequest.cs
│ ├── HttpResponse.cs
│ ├── HttpServer.cs
│ ├── HttpServerLib.csproj
│ ├── HttpService.cs
│ ├── ILogger.cs
│ ├── IServer.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Protocols.cs
│ ├── RequestHeaders.cs
│ ├── ResponseHeaders.cs
│ ├── ResponseHelper.cs
│ ├── RouteAttribute.cs
│ ├── RouteMethod.cs
│ ├── ServiceModule.cs
│ └── ServiceRoute.cs
├── Packages.dgml
└── Packages
│ ├── LitJson.0.7.0
│ ├── LitJson.0.7.0.nupkg
│ └── lib
│ │ └── LitJson.dll
│ └── repositories.config
├── README.md
└── sonar-project.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.pch
68 | *.pdb
69 | *.pgc
70 | *.pgd
71 | *.rsp
72 | *.sbr
73 | *.tlb
74 | *.tli
75 | *.tlh
76 | *.tmp
77 | *.tmp_proj
78 | *.log
79 | *.vspscc
80 | *.vssscc
81 | .builds
82 | *.pidb
83 | *.svclog
84 | *.scc
85 |
86 | # Chutzpah Test files
87 | _Chutzpah*
88 |
89 | # Visual C++ cache files
90 | ipch/
91 | *.aps
92 | *.ncb
93 | *.opendb
94 | *.opensdf
95 | *.sdf
96 | *.cachefile
97 | *.VC.db
98 | *.VC.VC.opendb
99 |
100 | # Visual Studio profiler
101 | *.psess
102 | *.vsp
103 | *.vspx
104 | *.sap
105 |
106 | # Visual Studio Trace Files
107 | *.e2e
108 |
109 | # TFS 2012 Local Workspace
110 | $tf/
111 |
112 | # Guidance Automation Toolkit
113 | *.gpState
114 |
115 | # ReSharper is a .NET coding add-in
116 | _ReSharper*/
117 | *.[Rr]e[Ss]harper
118 | *.DotSettings.user
119 |
120 | # JustCode is a .NET coding add-in
121 | .JustCode
122 |
123 | # TeamCity is a build add-in
124 | _TeamCity*
125 |
126 | # DotCover is a Code Coverage Tool
127 | *.dotCover
128 |
129 | # AxoCover is a Code Coverage Tool
130 | .axoCover/*
131 | !.axoCover/settings.json
132 |
133 | # Visual Studio code coverage results
134 | *.coverage
135 | *.coveragexml
136 |
137 | # NCrunch
138 | _NCrunch_*
139 | .*crunch*.local.xml
140 | nCrunchTemp_*
141 |
142 | # MightyMoose
143 | *.mm.*
144 | AutoTest.Net/
145 |
146 | # Web workbench (sass)
147 | .sass-cache/
148 |
149 | # Installshield output folder
150 | [Ee]xpress/
151 |
152 | # DocProject is a documentation generator add-in
153 | DocProject/buildhelp/
154 | DocProject/Help/*.HxT
155 | DocProject/Help/*.HxC
156 | DocProject/Help/*.hhc
157 | DocProject/Help/*.hhk
158 | DocProject/Help/*.hhp
159 | DocProject/Help/Html2
160 | DocProject/Help/html
161 |
162 | # Click-Once directory
163 | publish/
164 |
165 | # Publish Web Output
166 | *.[Pp]ublish.xml
167 | *.azurePubxml
168 | # Note: Comment the next line if you want to checkin your web deploy settings,
169 | # but database connection strings (with potential passwords) will be unencrypted
170 | *.pubxml
171 | *.publishproj
172 |
173 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
174 | # checkin your Azure Web App publish settings, but sensitive information contained
175 | # in these scripts will be unencrypted
176 | PublishScripts/
177 |
178 | # NuGet Packages
179 | *.nupkg
180 | # The packages folder can be ignored because of Package Restore
181 | **/[Pp]ackages/*
182 | # except build/, which is used as an MSBuild target.
183 | !**/[Pp]ackages/build/
184 | # Uncomment if necessary however generally it will be regenerated when needed
185 | #!**/[Pp]ackages/repositories.config
186 | # NuGet v3's project.json files produces more ignorable files
187 | *.nuget.props
188 | *.nuget.targets
189 |
190 | # Microsoft Azure Build Output
191 | csx/
192 | *.build.csdef
193 |
194 | # Microsoft Azure Emulator
195 | ecf/
196 | rcf/
197 |
198 | # Windows Store app package directories and files
199 | AppPackages/
200 | BundleArtifacts/
201 | Package.StoreAssociation.xml
202 | _pkginfo.txt
203 | *.appx
204 |
205 | # Visual Studio cache files
206 | # files ending in .cache can be ignored
207 | *.[Cc]ache
208 | # but keep track of directories ending in .cache
209 | !*.[Cc]ache/
210 |
211 | # Others
212 | ClientBin/
213 | ~$*
214 | *~
215 | *.dbmdl
216 | *.dbproj.schemaview
217 | *.jfm
218 | *.pfx
219 | *.publishsettings
220 | orleans.codegen.cs
221 |
222 | # Since there are multiple workflows, uncomment next line to ignore bower_components
223 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
224 | #bower_components/
225 |
226 | # RIA/Silverlight projects
227 | Generated_Code/
228 |
229 | # Backup & report files from converting an old project file
230 | # to a newer Visual Studio version. Backup files are not needed,
231 | # because we have git ;-)
232 | _UpgradeReport_Files/
233 | Backup*/
234 | UpgradeLog*.XML
235 | UpgradeLog*.htm
236 |
237 | # SQL Server files
238 | *.mdf
239 | *.ldf
240 | *.ndf
241 |
242 | # Business Intelligence projects
243 | *.rdl.data
244 | *.bim.layout
245 | *.bim_*.settings
246 |
247 | # Microsoft Fakes
248 | FakesAssemblies/
249 |
250 | # GhostDoc plugin setting file
251 | *.GhostDoc.xml
252 |
253 | # Node.js Tools for Visual Studio
254 | .ntvs_analysis.dat
255 | node_modules/
256 |
257 | # TypeScript v1 declaration files
258 | typings/
259 |
260 | # Visual Studio 6 build log
261 | *.plg
262 |
263 | # Visual Studio 6 workspace options file
264 | *.opt
265 |
266 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
267 | *.vbw
268 |
269 | # Visual Studio LightSwitch build output
270 | **/*.HTMLClient/GeneratedArtifacts
271 | **/*.DesktopClient/GeneratedArtifacts
272 | **/*.DesktopClient/ModelManifest.xml
273 | **/*.Server/GeneratedArtifacts
274 | **/*.Server/ModelManifest.xml
275 | _Pvt_Extensions
276 |
277 | # Paket dependency manager
278 | .paket/paket.exe
279 | paket-files/
280 |
281 | # FAKE - F# Make
282 | .fake/
283 |
284 | # JetBrains Rider
285 | .idea/
286 | *.sln.iml
287 |
288 | # CodeRush
289 | .cr/
290 |
291 | # Python Tools for Visual Studio (PTVS)
292 | __pycache__/
293 | *.pyc
294 |
295 | # Cake - Uncomment if you are using it
296 | # tools/**
297 | # !tools/packages.config
298 |
299 | # Tabs Studio
300 | *.tss
301 |
302 | # Telerik's JustMock configuration file
303 | *.jmconfig
304 |
305 | # BizTalk build output
306 | *.btp.cs
307 | *.btm.cs
308 | *.odx.cs
309 | *.xsd.cs
310 |
311 | # OpenCover UI analysis results
312 | OpenCover/
313 |
314 | # Azure Stream Analytics local run output
315 | ASALocalRun/
316 | sonar.bat
317 | .sonarqube
318 |
--------------------------------------------------------------------------------
/.scannerwork/.sonar_lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qinyuanpei/HttpServer/f5decb7b887b3afe1b9ec55b29b8a73112851bbd/.scannerwork/.sonar_lock
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | jdk:
2 | - oraclejdk8
3 | mono:
4 | - latest
5 |
6 | language: csharp
7 | solution: ./HTTPServer/HTTPServer.sln
8 |
9 | notifications:
10 | email:
11 | recipients:
12 | - 875974254@qq.com
13 | - qinyuanpei@163.com
14 | on_success: change # default: change
15 | on_failure: always # default: always
16 |
17 | install:
18 | - cd ./HTTPServer
19 | - nuget restore ./HTTPServer.sln # restore nuget
20 | # - nuget install NUnit.Runners -Version 3.8.0 -OutputDirectory ./TestRunner # install nunit
21 |
22 | script:
23 | - msbuild /p:Configuration=Release HTTPServer.sln
24 | # - mono ./TestRunner/NUnit.ConsoleRunner.3.8.0/tools/nunit3-console.exe ./HTTPServerLib.UnitTest/bin/Release/HttpServerLib.UnitTest.dll
25 | # - sonar-scanner -Dsonar.verbose=true -X
26 |
27 | branches:
28 | only:
29 | - master
30 |
31 | addons:
32 | sonarcloud:
33 | organization: "qinyuanpei-github"
34 | token: db795a28468dc7c12805b330afed53d362fdd2d9
35 |
36 | cache:
37 | directories:
38 | - '$HOME/.sonar/cache'
39 |
40 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:14.04
2 | LABEL vendor="qinyuanpei@163.com"
3 |
4 | # Install Mono && XBuild
5 | RUN sudo apt-get update
6 | RUN sudo apt-get upgrade -y
7 | RUN sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
8 | RUN sudo apt install apt-transport-https -y
9 | RUN sudo apt-get install wget -y
10 | RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-trusty main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
11 | RUN sudo apt-get update
12 | RUN sudo apt-get install aptitude -y
13 | RUN sudo apt-get install -f
14 | RUN sudo apt-get install -y git
15 | RUN sudo apt-get install -y zip
16 | RUN sudo apt-get install -y unzip
17 | RUN sudo aptitude install -y mono-complete
18 |
19 | # Intall Nuget
20 | RUN sudo mkdir /usr/nuget/
21 | RUN sudo wget -O /usr/nuget/nuget.exe https://dist.nuget.org/win-x86-commandline/v4.6.2/nuget.exe
22 | ENV NUGET="/usr/nuget/nuget.exe"
23 |
24 | # Install Sonar-Scanner
25 | RUN sudo wget -O sonar-scanner.zip https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.2.0.1227-linux.zip
26 | RUN sudo unzip sonar-scanner.zip -d /usr/
27 | RUN sudo chmod -R 777 usr/sonar-scanner-3.2.0.1227-linux
28 | ENV SONAR_SCANNER="usr/sonar-scanner-3.2.0.1227-linux/bin/sonar-scanner"
29 |
30 | # Install NUnit
31 | RUN mono ${NUGET} install NUnit.Runners -Version 3.8.0 -OutputDirectory ./TestRunner
32 | ENV NUNIT="./TestRunner/NUnit.ConsoleRunner.3.8.0/tools/nunit3-console.exe"
33 |
34 | # Build Project && Sonar Analyse && UnitTest
35 | RUN sudo mkdir ./WorkSpace/
36 | RUN cd ./WorkSpace/
37 | RUN sudo chmod -R 777 ./WorkSpace/
38 | RUN git clone https://github.com/qinyuanpei/HttpServer.git
39 | RUN cd ./HttpServer/
40 | RUN sudo ${SONAR_SCANNER} -D sonar.host.url="https://sonarcloud.io" -D sonar.login="db795a28468dc7c12805b330afed53d362fdd2d9" -D sonar.projectKey="Sonar-HttpServer" -D sonar.sources="." -D sonar.projectName="HttpServer" -X
41 | RUN msbuild /p:Configuration=Release ./HTTPServer/HTTPServer.sln
42 | RUN mono ${NUNIT} ./HTTPServer/HTTPServerLib.UnitTest/bin/Release/HttpServerLib.UnitTest.dll
43 | EXPOSE 2048
44 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPClient/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPClient/HttpClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B2A1D446-92CE-455C-9194-36C8EF225D9C}
8 | Exe
9 | Properties
10 | HttpClient
11 | HttpClient
12 | v4.6
13 | 512
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
59 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPClient/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace HttpClient
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | var request = (HttpWebRequest)WebRequest.Create("http://localhost:4050/");
16 | request.Method = "POST";
17 | var requestStream = request.GetRequestStream();
18 | var data = Encoding.UTF8.GetBytes("a=10&b=15");
19 | requestStream.Write(data, 0, data.Length);
20 | var response = request.GetResponse();
21 |
22 | using (StreamReader reader = new StreamReader(response.GetResponseStream()))
23 | {
24 | var content = reader.ReadToEnd();
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPClient/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("HttpClient")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HttpClient")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("71086c2e-79d1-414c-b070-c8bcb457a0e2")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPClient/bin/Debug/HttpClient.exe.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpServer", "HTTPServer\HttpServer.csproj", "{E6E5FC8E-8B94-4F1E-91BB-750B40ACB96E}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpServerLib", "HTTPServerLib\HttpServerLib.csproj", "{C2310E13-8D59-4632-BF91-203BFF2FFE4F}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpServerLib.UnitTest", "HTTPServerLib.UnitTest\HttpServerLib.UnitTest.csproj", "{31021B42-4303-4358-9EE2-60B1A0215AC8}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpClient", "HTTPClient\HttpClient.csproj", "{B2A1D446-92CE-455C-9194-36C8EF225D9C}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {E6E5FC8E-8B94-4F1E-91BB-750B40ACB96E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {E6E5FC8E-8B94-4F1E-91BB-750B40ACB96E}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {E6E5FC8E-8B94-4F1E-91BB-750B40ACB96E}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {E6E5FC8E-8B94-4F1E-91BB-750B40ACB96E}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {C2310E13-8D59-4632-BF91-203BFF2FFE4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {C2310E13-8D59-4632-BF91-203BFF2FFE4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {C2310E13-8D59-4632-BF91-203BFF2FFE4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {C2310E13-8D59-4632-BF91-203BFF2FFE4F}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {31021B42-4303-4358-9EE2-60B1A0215AC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {31021B42-4303-4358-9EE2-60B1A0215AC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {31021B42-4303-4358-9EE2-60B1A0215AC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {31021B42-4303-4358-9EE2-60B1A0215AC8}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {B2A1D446-92CE-455C-9194-36C8EF225D9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {B2A1D446-92CE-455C-9194-36C8EF225D9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {B2A1D446-92CE-455C-9194-36C8EF225D9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {B2A1D446-92CE-455C-9194-36C8EF225D9C}.Release|Any CPU.Build.0 = Release|Any CPU
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | EndGlobal
39 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer/ConsoleLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HTTPServerLib;
7 |
8 | namespace HttpServer
9 | {
10 | public class ConsoleLogger:ILogger
11 | {
12 | public void Log(object message)
13 | {
14 | Console.WriteLine(message);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer/ExampleServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HTTPServerLib;
7 | using System.IO;
8 |
9 | namespace HttpServer
10 | {
11 | public class ExampleServer : HTTPServerLib.HttpServer
12 | {
13 | ///
14 | /// 构造函数
15 | ///
16 | /// IP地址
17 | /// 端口号
18 | public ExampleServer(string ipAddress, int port)
19 | : base(ipAddress, port)
20 | {
21 |
22 | }
23 |
24 | public override void OnPost(HttpRequest request, HttpResponse response)
25 | {
26 | //获取客户端传递的参数
27 | string data = request.Params == null ? "" : string.Join(";", request.Params.Select(x => x.Key + "=" + x.Value).ToArray());
28 |
29 | //设置返回信息
30 | string content = string.Format("这是通过Post方式返回的数据:{0}", data);
31 |
32 | //构造响应报文
33 | response.SetContent(content);
34 | response.Content_Encoding = "utf-8";
35 | response.StatusCode = "200";
36 | response.Content_Type = "text/html; charset=UTF-8";
37 | response.Headers["Server"] = "ExampleServer";
38 |
39 | //发送响应
40 | response.Send();
41 | }
42 |
43 | public override void OnGet(HttpRequest request, HttpResponse response)
44 | {
45 |
46 | ///链接形式1:"http://localhost:4050/assets/styles/style.css"表示访问指定文件资源,
47 | ///此时读取服务器目录下的/assets/styles/style.css文件。
48 |
49 | ///链接形式1:"http://localhost:4050/assets/styles/"表示访问指定页面资源,
50 | ///此时读取服务器目录下的/assets/styles/style.index文件。
51 |
52 | //当文件不存在时应返回404状态码
53 | string requestURL = request.URL;
54 | requestURL = requestURL.Replace("/", @"\").Replace("\\..", "").TrimStart('\\');
55 | string requestFile = Path.Combine(ServerRoot, requestURL);
56 |
57 | //判断地址中是否存在扩展名
58 | string extension = Path.GetExtension(requestFile);
59 |
60 | //根据有无扩展名按照两种不同链接进行处
61 | if (extension != "")
62 | {
63 | //从文件中返回HTTP响应
64 | response = response.FromFile(requestFile);
65 | }
66 | else
67 | {
68 | //目录存在且不存在index页面时时列举目录
69 | if (Directory.Exists(requestFile) && !File.Exists(requestFile + "\\index.html"))
70 | {
71 | requestFile = Path.Combine(ServerRoot, requestFile);
72 | var content = ListDirectory(requestFile, requestURL);
73 | response = response.SetContent(content, Encoding.UTF8);
74 | response.Content_Type = "text/html; charset=UTF-8";
75 | }
76 | else
77 | {
78 | //加载静态HTML页面
79 | requestFile = Path.Combine(requestFile, "index.html");
80 | response = response.FromFile(requestFile);
81 | response.Content_Type = "text/html; charset=UTF-8";
82 | }
83 | }
84 |
85 | //发送HTTP响应
86 | response.Send();
87 | }
88 |
89 | public override void OnDefault(HttpRequest request, HttpResponse response)
90 | {
91 |
92 | }
93 |
94 | private string ConvertPath(string[] urls)
95 | {
96 | string html = string.Empty;
97 | int length = ServerRoot.Length;
98 | foreach (var url in urls)
99 | {
100 | var s = url.StartsWith("..") ? url : url.Substring(length).TrimEnd('\\');
101 | html += String.Format("
{0}", s);
102 | }
103 |
104 | return html;
105 | }
106 |
107 | private string ListDirectory(string requestDirectory, string requestURL)
108 | {
109 | //列举子目录
110 | var folders = requestURL.Length > 1 ? new string[] { "../" } : new string[] { };
111 | folders = folders.Concat(Directory.GetDirectories(requestDirectory)).ToArray();
112 | var foldersList = ConvertPath(folders);
113 |
114 | //列举文件
115 | var files = Directory.GetFiles(requestDirectory);
116 | var filesList = ConvertPath(files);
117 |
118 | //构造HTML
119 | StringBuilder builder = new StringBuilder();
120 | builder.Append(string.Format("{0}", requestDirectory));
121 | builder.Append(string.Format("{0}
",
122 | requestURL, filesList, foldersList));
123 |
124 | return builder.ToString();
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer/HttpServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E6E5FC8E-8B94-4F1E-91BB-750B40ACB96E}
8 | Exe
9 | Properties
10 | HttpServer
11 | HttpServer
12 | v4.6
13 | 512
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {c2310e13-8d59-4632-bf91-203bff2ffe4f}
57 | HttpServerLib
58 |
59 |
60 |
61 |
68 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HTTPServerLib;
7 | using HttpServer;
8 |
9 | namespace HTTPServerLib
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | ExampleServer server = new ExampleServer("0.0.0.0", 4050);
16 | server.SetRoot(@"D:\Hexo\public");
17 | server.Logger = new ConsoleLogger();
18 | server.Start();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("HTTPServer")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HTTPServer")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("c0256988-62e5-447f-b056-09288e77950e")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServer/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib.UnitTest/HttpServerLib.UnitTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {31021B42-4303-4358-9EE2-60B1A0215AC8}
7 | Library
8 | Properties
9 | HttpServerLib.UnitTest
10 | HttpServerLib.UnitTest
11 | v4.6
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 | ..\packages\NUnit.3.8.0\lib\net45\nunit.framework.dll
41 | True
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | False
66 |
67 |
68 | False
69 |
70 |
71 | False
72 |
73 |
74 | False
75 |
76 |
77 |
78 |
79 |
80 |
81 |
88 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib.UnitTest/HttpServerTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NUnit.Framework;
3 | using System.Net;
4 | using System.Text;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Collections.Generic;
8 | using System.Text.RegularExpressions;
9 |
10 | namespace HTTPServerLib.UnitTest
11 | {
12 | [TestFixture]
13 | public class HttpServerTest
14 | {
15 | [Test]
16 | public void TestGet()
17 | {
18 | var request = (HttpWebRequest)WebRequest.Create("http://localhost:4050/");
19 | var response = request.GetResponse();
20 | Assert.AreEqual("text/html; charset=UTF-8", response.Headers["Content-Type"]);
21 | Assert.AreEqual("ExampleServer", response.Headers["Server"]);
22 | }
23 |
24 | [Test]
25 | public void TestPost()
26 | {
27 | var request = (HttpWebRequest)WebRequest.Create("http://localhost:4050/");
28 | request.Method = "POST";
29 | var requestStream = request.GetRequestStream();
30 | var data = Encoding.UTF8.GetBytes("a=10&b=15");
31 | requestStream.Write(data,0,data.Length);
32 | var response = request.GetResponse();
33 | Assert.AreEqual("text/html; charset=UTF-8", response.Headers["Content-Type"]);
34 | Assert.AreEqual("ExampleServer", response.Headers["Server"]);
35 | using (StreamReader reader = new StreamReader(response.GetResponseStream()))
36 | {
37 | var content = reader.ReadToEnd();
38 | Assert.AreEqual("这是通过Post方式返回的数据:a=10;b=15", content);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib.UnitTest/HttpServiceTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using NUnit.Framework;
5 |
6 | namespace HttpServerLib.UnitTest
7 | {
8 | [TestFixture]
9 | public class HttpServiceTest
10 | {
11 |
12 | [Test]
13 | public void TestGet()
14 | {
15 |
16 | }
17 |
18 | [Test]
19 | public void TestPost()
20 | {
21 |
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib.UnitTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下特性集
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("HTTPServerLib.UnitTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HTTPServerLib.UnitTest")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
19 | // 请将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("c7d7cd2e-b24f-4761-9562-6ea8edd8287c")]
24 |
25 | // 程序集的版本信息由以下四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib.UnitTest/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/ActionResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public class ActionResult
10 | {
11 | public object Result { get; set; }
12 | public bool Success { get; set; }
13 | public string Message { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/BaseHeader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public class BaseHeader
10 | {
11 | public string Body { get; set; }
12 |
13 | public Encoding Encoding { get; set; }
14 |
15 | public string Content_Type { get; set; }
16 |
17 | public string Content_Length { get; set; }
18 |
19 | public string Content_Encoding { get; set; }
20 |
21 | public string ContentLanguage { get; set; }
22 |
23 | public Dictionary Headers { get; set; }
24 |
25 | ///
26 | /// 不支持枚举类型约束,所以采取下列方案:)
27 | ///
28 | protected string GetHeaderByKey(Enum header)
29 | {
30 | var fieldName = header.GetDescription();
31 | if (fieldName == null) return null;
32 | var hasKey = Headers.ContainsKey(fieldName);
33 | if (!hasKey) return null;
34 | return Headers[fieldName];
35 | }
36 |
37 | protected string GetHeaderByKey(string fieldName)
38 | {
39 | if (string.IsNullOrEmpty(fieldName)) return null;
40 | var hasKey = Headers.ContainsKey(fieldName);
41 | if (!hasKey) return null;
42 | return Headers[fieldName];
43 | }
44 |
45 | ///
46 | /// 不支持枚举类型约束,所以采取下列方案:)
47 | ///
48 | protected void SetHeaderByKey(Enum header, string value)
49 | {
50 | var fieldName = header.GetDescription();
51 | if (fieldName == null) return;
52 | var hasKey = Headers.ContainsKey(fieldName);
53 | if (!hasKey) Headers.Add(fieldName, value);
54 | Headers[fieldName] = value;
55 | }
56 |
57 | protected void SetHeaderByKey(string fieldName, string value)
58 | {
59 | if (string.IsNullOrEmpty(fieldName)) return;
60 | var hasKey = Headers.ContainsKey(fieldName);
61 | if (!hasKey) Headers.Add(fieldName, value);
62 | Headers[fieldName] = value;
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/HeadersHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace HTTPServerLib
9 | {
10 | public static class HeadersHelper
11 | {
12 | public static string GetDescription(this Enum value)
13 | {
14 | var valueType = value.GetType();
15 | var memberName = Enum.GetName(valueType, value);
16 | if (memberName == null) return null;
17 | var fieldInfo = valueType.GetField(memberName);
18 | var attribute = Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute));
19 | if (attribute == null) return null;
20 | return (attribute as DescriptionAttribute).Description;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/HttpRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Net.Sockets;
7 | using System.IO;
8 | using System.Text.RegularExpressions;
9 |
10 | namespace HTTPServerLib
11 | {
12 | ///
13 | /// HTTP请求定义
14 | ///
15 | public class HttpRequest : BaseHeader
16 | {
17 | ///
18 | /// URL参数
19 | ///
20 | public Dictionary Params { get; private set; }
21 |
22 | ///
23 | /// HTTP请求方式
24 | ///
25 | public string Method { get; private set; }
26 |
27 | ///
28 | /// HTTP(S)地址
29 | ///
30 | public string URL { get; set; }
31 |
32 | ///
33 | /// HTTP协议版本
34 | ///
35 | public string ProtocolVersion { get; set; }
36 |
37 | ///
38 | /// 定义缓冲区
39 | ///
40 | private const int MAX_SIZE = 1024 * 1024 * 2;
41 | private byte[] bytes = new byte[MAX_SIZE];
42 |
43 | public ILogger Logger { get; set; }
44 |
45 | private Stream handler;
46 |
47 | public HttpRequest(Stream stream)
48 | {
49 | this.handler = stream;
50 | var data = GetRequestData(handler);
51 | var rows = Regex.Split(data, Environment.NewLine);
52 |
53 | //Request URL & Method & Version
54 | var first = Regex.Split(rows[0], @"(\s+)")
55 | .Where(e => e.Trim() != string.Empty)
56 | .ToArray();
57 | if (first.Length > 0) this.Method = first[0];
58 | if (first.Length > 1) this.URL = Uri.UnescapeDataString(first[1]);
59 | if (first.Length > 2) this.ProtocolVersion = first[2];
60 |
61 | //Request Headers
62 | this.Headers = GetRequestHeaders(rows);
63 |
64 | //Request Body
65 | Body = GetRequestBody(rows);
66 | var contentLength = GetHeader(RequestHeaders.ContentLength);
67 | if (int.TryParse(contentLength, out var length) && Body.Length != length)
68 | {
69 | do
70 | {
71 | length = stream.Read(bytes, 0, MAX_SIZE - 1);
72 | Body += Encoding.UTF8.GetString(bytes, 0, length);
73 | } while (Body.Length != length);
74 | }
75 |
76 | //Request "GET"
77 | if (this.Method == "GET")
78 | {
79 | var isUrlencoded = this.URL.Contains('?');
80 | if (isUrlencoded) this.Params = GetRequestParameters(URL.Split('?')[1]);
81 | }
82 |
83 | //Request "POST"
84 | if (this.Method == "POST")
85 | {
86 | var contentType = GetHeader(RequestHeaders.ContentType);
87 | var isUrlencoded = contentType == @"application/x-www-form-urlencoded";
88 | if (isUrlencoded) this.Params = GetRequestParameters(this.Body);
89 | }
90 | }
91 |
92 | public Stream GetRequestStream()
93 | {
94 | return this.handler;
95 | }
96 |
97 | public string GetHeader(RequestHeaders header)
98 | {
99 | return GetHeaderByKey(header);
100 | }
101 |
102 | public string GetHeader(string fieldName)
103 | {
104 | return GetHeaderByKey(fieldName);
105 | }
106 |
107 | public void SetHeader(RequestHeaders header, string value)
108 | {
109 | SetHeaderByKey(header, value);
110 | }
111 |
112 | public void SetHeader(string fieldName,string value)
113 | {
114 | SetHeaderByKey(fieldName, value);
115 | }
116 |
117 | private string GetRequestData(Stream stream)
118 | {
119 | var length = 0;
120 | var data = string.Empty;
121 |
122 | do
123 | {
124 | length = stream.Read(bytes, 0, MAX_SIZE - 1);
125 | data += Encoding.UTF8.GetString(bytes, 0, length);
126 | } while (length > 0 && !data.Contains("\r\n\r\n"));
127 |
128 | return data;
129 | }
130 |
131 | private string GetRequestBody(IEnumerable rows)
132 | {
133 | var target = rows.Select((v, i) => new { Value = v, Index = i }).FirstOrDefault(e => e.Value.Trim() == string.Empty);
134 | if (target == null) return null;
135 | var range = Enumerable.Range(target.Index + 1, rows.Count() - target.Index - 1);
136 | return string.Join(Environment.NewLine, range.Select(e => rows.ElementAt(e)).ToArray());
137 | }
138 |
139 | private Dictionary GetRequestHeaders(IEnumerable rows)
140 | {
141 | if (rows == null || rows.Count() <= 0) return null;
142 | var target = rows.Select((v, i) => new { Value = v, Index = i }).FirstOrDefault(e => e.Value.Trim() == string.Empty);
143 | var length = target == null ? rows.Count() - 1 : target.Index;
144 | if (length <= 1) return null;
145 | var range = Enumerable.Range(1, length - 1);
146 | return range.Select(e => rows.ElementAt(e)).ToDictionary(e => e.Split(':')[0], e => e.Split(':')[1].Trim());
147 | }
148 |
149 | private Dictionary GetRequestParameters(string row)
150 | {
151 | if (string.IsNullOrEmpty(row)) return null;
152 | var kvs = Regex.Split(row, "&");
153 | if (kvs == null || kvs.Count() <= 0) return null;
154 |
155 | return kvs.ToDictionary(e => Regex.Split(e, "=")[0], e => { var p = Regex.Split(e, "="); return p.Length > 1 ? p[1] : ""; });
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/HttpResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace HTTPServerLib
9 | {
10 | public class HttpResponse : BaseHeader
11 | {
12 | public string StatusCode { get; set; }
13 |
14 | public string Protocols { get; set; }
15 |
16 | public string ProtocolsVersion { get; set; }
17 |
18 | public byte[] Content { get; private set; }
19 |
20 | private Stream handler;
21 |
22 | public ILogger Logger { get; set; }
23 |
24 | public HttpResponse(Stream stream)
25 | {
26 | this.handler = stream;
27 | this.Headers = new Dictionary();
28 | }
29 |
30 | public HttpResponse SetContent(byte[] content, Encoding encoding = null)
31 | {
32 | this.Content = content;
33 | this.Encoding = encoding != null ? encoding : Encoding.UTF8;
34 | this.Content_Length = content.Length.ToString();
35 | return this;
36 | }
37 |
38 | public HttpResponse SetContent(string content, Encoding encoding = null)
39 | {
40 | //初始化内容
41 | encoding = encoding != null ? encoding : Encoding.UTF8;
42 | return SetContent(encoding.GetBytes(content), encoding);
43 | }
44 |
45 | public Stream GetResponseStream()
46 | {
47 | return this.handler;
48 | }
49 |
50 | public string GetHeader(ResponseHeaders header)
51 | {
52 | return GetHeaderByKey(header);
53 | }
54 |
55 | public string GetHeader(string fieldName)
56 | {
57 | return GetHeaderByKey(fieldName);
58 | }
59 |
60 | public void SetHeader(ResponseHeaders header, string value)
61 | {
62 | SetHeaderByKey(header, value);
63 | }
64 |
65 | public void SetHeader(string fieldName, string value)
66 | {
67 | SetHeaderByKey(fieldName, value);
68 | }
69 |
70 | ///
71 | /// 构建响应头部
72 | ///
73 | ///
74 | protected string BuildHeader()
75 | {
76 | StringBuilder builder = new StringBuilder();
77 |
78 | if (!string.IsNullOrEmpty(StatusCode))
79 | builder.Append("HTTP/1.1 " + StatusCode + "\r\n");
80 |
81 | if (!string.IsNullOrEmpty(this.Content_Type))
82 | builder.AppendLine("Content-Type:" + this.Content_Type);
83 | return builder.ToString();
84 | }
85 |
86 | ///
87 | /// 发送数据
88 | ///
89 | public void Send()
90 | {
91 | if (!handler.CanWrite) return;
92 |
93 | try
94 | {
95 | //发送响应头
96 | var header = BuildHeader();
97 | byte[] headerBytes = this.Encoding.GetBytes(header);
98 | handler.Write(headerBytes, 0, headerBytes.Length);
99 |
100 | //发送空行
101 | byte[] lineBytes = this.Encoding.GetBytes(System.Environment.NewLine);
102 | handler.Write(lineBytes, 0, lineBytes.Length);
103 |
104 | //发送内容
105 | handler.Write(Content, 0, Content.Length);
106 | }
107 | catch (Exception e)
108 | {
109 | Log(e.Message);
110 | }
111 | finally
112 | {
113 | handler.Close();
114 | }
115 | }
116 |
117 | ///
118 | /// 记录日志
119 | ///
120 | /// 日志消息
121 | private void Log(object message)
122 | {
123 | if (Logger != null)
124 | Logger.Log(message);
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/HttpServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Net;
4 | using System.Net.Security;
5 | using System.Net.Sockets;
6 | using System.Security.Authentication;
7 | using System.Security.Cryptography.X509Certificates;
8 | using System.Threading;
9 | using System.Runtime.InteropServices;
10 |
11 | namespace HTTPServerLib
12 | {
13 |
14 | public class HttpServer : IServer
15 | {
16 | ///
17 | /// 服务器IP
18 | ///
19 | public string ServerIP { get; private set; }
20 |
21 | ///
22 | /// 服务器端口
23 | ///
24 | public int ServerPort { get; private set; }
25 |
26 | ///
27 | /// 服务器目录
28 | ///
29 | public string ServerRoot { get; private set; }
30 |
31 | ///
32 | /// 是否运行
33 | ///
34 | public bool IsRunning { get; private set; }
35 |
36 | ///
37 | /// 服务器协议
38 | ///
39 | public Protocols Protocol { get; private set; }
40 |
41 | ///
42 | /// 服务端Socet
43 | ///
44 | private TcpListener serverListener;
45 |
46 | ///
47 | /// 日志接口
48 | ///
49 | public ILogger Logger { get; set; }
50 |
51 | ///
52 | /// SSL证书
53 | ///
54 | private X509Certificate serverCertificate = null;
55 |
56 | ///
57 | /// 构造函数
58 | ///
59 | /// IP地址
60 | /// 端口号
61 | /// 根目录
62 | private HttpServer(IPAddress ipAddress, int port, string root)
63 | {
64 | this.ServerIP = ipAddress.ToString();
65 | this.ServerPort = port;
66 |
67 | //如果指定目录不存在则采用默认目录
68 | if (!Directory.Exists(root))
69 | this.ServerRoot = AppDomain.CurrentDomain.BaseDirectory;
70 |
71 | this.ServerRoot = root;
72 | }
73 |
74 | ///
75 | /// 构造函数
76 | ///
77 | /// IP地址
78 | /// 端口号
79 | /// 根目录
80 | public HttpServer(string ipAddress, int port, string root) :
81 | this(IPAddress.Parse(ipAddress), port, root)
82 | { }
83 |
84 | ///
85 | /// 构造函数
86 | ///
87 | /// IP地址
88 | /// 端口号
89 | public HttpServer(string ipAddress, int port) :
90 | this(IPAddress.Parse(ipAddress), port, AppDomain.CurrentDomain.BaseDirectory)
91 | { }
92 |
93 |
94 | ///
95 | /// 构造函数
96 | ///
97 | /// 端口号
98 | /// 根目录
99 | public HttpServer(int port, string root) :
100 | this(IPAddress.Loopback, port, root)
101 | { }
102 |
103 | ///
104 | /// 构造函数
105 | ///
106 | /// 端口号
107 | public HttpServer(int port) :
108 | this(IPAddress.Loopback, port, AppDomain.CurrentDomain.BaseDirectory)
109 | { }
110 |
111 |
112 | ///
113 | /// 构造函数
114 | ///
115 | ///
116 | public HttpServer(string ip) :
117 | this(IPAddress.Parse(ip), 80, AppDomain.CurrentDomain.BaseDirectory)
118 | { }
119 |
120 | #region 公开方法
121 |
122 | ///
123 | /// 开启服务器
124 | ///
125 | public void Start()
126 | {
127 | if (IsRunning) return;
128 |
129 | //创建服务端Socket
130 | this.serverListener = new TcpListener(IPAddress.Parse(ServerIP), ServerPort);
131 | this.Protocol = serverCertificate == null ? Protocols.Http : Protocols.Https;
132 | this.IsRunning = true;
133 | this.serverListener.Start();
134 | this.Log(string.Format("Sever is running at {0}://{1}:{2}", Protocol.ToString().ToLower(), ServerIP, ServerPort));
135 |
136 | try
137 | {
138 | while (IsRunning)
139 | {
140 | TcpClient client = serverListener.AcceptTcpClient();
141 | Thread requestThread = new Thread(() => { ProcessRequest(client); });
142 | requestThread.Start();
143 | }
144 | }
145 | catch (Exception e)
146 | {
147 | Log(e.Message);
148 | }
149 | }
150 |
151 |
152 | public HttpServer SetSSL(string certificate)
153 | {
154 | return SetSSL(X509Certificate.CreateFromCertFile(certificate));
155 | }
156 |
157 |
158 | public HttpServer SetSSL(X509Certificate certifiate)
159 | {
160 | this.serverCertificate = certifiate;
161 | return this;
162 | }
163 |
164 | public void Stop()
165 | {
166 | if (!IsRunning) return;
167 |
168 | IsRunning = false;
169 | serverListener.Stop();
170 | }
171 |
172 | ///
173 | /// 设置服务器目录
174 | ///
175 | ///
176 | public HttpServer SetRoot(string root)
177 | {
178 | if (!Directory.Exists(root))
179 | this.ServerRoot = AppDomain.CurrentDomain.BaseDirectory;
180 |
181 | this.ServerRoot = root;
182 | return this;
183 | }
184 | ///
185 | /// 获取服务器目录
186 | ///
187 | public string GetRoot()
188 | {
189 | return this.ServerRoot;
190 | }
191 |
192 | ///
193 | /// 设置端口
194 | ///
195 | /// 端口号
196 | ///
197 | public HttpServer SetPort(int port)
198 | {
199 | this.ServerPort = port;
200 | return this;
201 | }
202 |
203 |
204 | #endregion
205 |
206 | #region 内部方法
207 |
208 | ///
209 | /// 处理客户端请求
210 | ///
211 | /// 客户端Socket
212 | private void ProcessRequest(TcpClient handler)
213 | {
214 | //处理请求
215 | Stream clientStream = handler.GetStream();
216 |
217 | //处理SSL
218 | if (serverCertificate != null) clientStream = ProcessSSL(clientStream);
219 | if (clientStream == null) return;
220 |
221 | //构造HTTP请求
222 | HttpRequest request = new HttpRequest(clientStream);
223 | request.Logger = Logger;
224 |
225 | //构造HTTP响应
226 | HttpResponse response = new HttpResponse(clientStream);
227 | response.Logger = Logger;
228 |
229 | //处理请求类型
230 | switch (request.Method)
231 | {
232 | case "GET":
233 | OnGet(request, response);
234 | break;
235 | case "POST":
236 | OnPost(request, response);
237 | break;
238 | default:
239 | OnDefault(request, response);
240 | break;
241 | }
242 | }
243 |
244 |
245 | ///
246 | /// 处理ssl加密请求
247 | ///
248 | ///
249 | ///
250 | private Stream ProcessSSL(Stream clientStream)
251 | {
252 | try
253 | {
254 | SslStream sslStream = new SslStream(clientStream);
255 | sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, true);
256 | sslStream.ReadTimeout = 10000;
257 | sslStream.WriteTimeout = 10000;
258 | return sslStream;
259 | }
260 | catch (Exception e)
261 | {
262 | Log(e.Message);
263 | clientStream.Close();
264 | }
265 |
266 | return null;
267 | }
268 |
269 | ///
270 | /// 记录日志
271 | ///
272 | /// 日志消息
273 | protected void Log(object message)
274 | {
275 | if (Logger != null) Logger.Log(message);
276 | }
277 |
278 | #endregion
279 |
280 | #region 虚方法
281 |
282 | ///
283 | /// 响应Get请求
284 | ///
285 | /// 请求报文
286 | public virtual void OnGet(HttpRequest request, HttpResponse response)
287 | {
288 |
289 | }
290 |
291 | ///
292 | /// 响应Post请求
293 | ///
294 | ///
295 | public virtual void OnPost(HttpRequest request, HttpResponse response)
296 | {
297 |
298 | }
299 |
300 | ///
301 | /// 响应默认请求
302 | ///
303 |
304 | public virtual void OnDefault(HttpRequest request, HttpResponse response)
305 | {
306 |
307 | }
308 |
309 | #endregion
310 | }
311 | }
312 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/HttpServerLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C2310E13-8D59-4632-BF91-203BFF2FFE4F}
8 | Library
9 | Properties
10 | HTTPServerLib
11 | HttpServerLib
12 | v4.6
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
70 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/HttpService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public class HttpService : HttpServer
10 | {
11 | private List m_modules;
12 |
13 | public HttpService(string ipAddress, int port)
14 | : base(ipAddress, port)
15 | {
16 | m_modules = new List();
17 | }
18 |
19 | ///
20 | /// 注册模块
21 | ///
22 | /// ServiceModule
23 | public void RegisterModule(ServiceModule module)
24 | {
25 | this.m_modules.Add(module);
26 | }
27 |
28 | ///
29 | /// 卸载模块
30 | ///
31 | ///
32 | public void RemoveModule(ServiceModule module)
33 | {
34 | this.m_modules.Remove(module);
35 | }
36 |
37 | public override void OnDefault(HttpRequest request, HttpResponse response)
38 | {
39 | base.OnDefault(request, response);
40 | }
41 |
42 | public override void OnGet(HttpRequest request, HttpResponse response)
43 | {
44 | ServiceRoute route = ServiceRoute.Parse(request);
45 | ServiceModule module = m_modules.FirstOrDefault(m => m.SearchRoute(route));
46 | if (module != null){
47 | var result = module.ExecuteRoute(route);
48 | }
49 | }
50 |
51 | public override void OnPost(HttpRequest request, HttpResponse response)
52 | {
53 | base.OnPost(request, response);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/ILogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public interface ILogger
10 | {
11 | void Log(object message);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/IServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public interface IServer
10 | {
11 | ///
12 | /// 响应GET方法
13 | ///
14 | /// Http请求
15 | void OnGet(HttpRequest request, HttpResponse response);
16 |
17 |
18 | ///
19 | /// 响应Post方法
20 | ///
21 | /// Http请求
22 | void OnPost(HttpRequest request, HttpResponse response);
23 |
24 |
25 | ///
26 | /// 响应默认请求
27 | ///
28 | /// Http请求
29 | void OnDefault(HttpRequest request, HttpResponse response);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的常规信息通过以下
6 | // 特性集控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("HttpServerLib")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HttpServerLib")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 使此程序集中的类型
18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
19 | // 则将该类型上的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("ed455757-2cb9-4206-bb94-0db98ce9c917")]
24 |
25 | // 程序集的版本信息由下面四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/Protocols.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public enum Protocols
10 | {
11 | Http = 0,
12 |
13 | Https = 1
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/RequestHeaders.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace HTTPServerLib
9 | {
10 | public enum RequestHeaders
11 | {
12 | ///
13 | /// Cache-Control 标头,指定请求/响应链上所有缓存控制机制必须服从的指令。
14 | ///
15 | [Description("Cache-Control")]
16 | CacheControl = 0,
17 |
18 | ///
19 | /// Connection 标头,指定特定连接需要的选项。
20 | ///
21 | [Description("Connection")]
22 | Connection = 1,
23 |
24 | ///
25 | /// Date 标头,指定开始创建请求的日期和时间。
26 | ///
27 | [Description("Date")]
28 | Date = 2,
29 |
30 | ///
31 | /// Keep-Alive 标头,指定用以维护持久性连接的参数。
32 | ///
33 | [Description("Keep-Alive")]
34 | KeepAlive = 3,
35 |
36 | ///
37 | /// Pragma 标头,指定可应用于请求/响应链上的任何代理的特定于实现的指令。
38 | ///
39 | [Description("Pragma")]
40 | Pragma = 4,
41 |
42 | ///
43 | /// Trailer 标头,指定标头字段显示在以 chunked 传输编码方式编码的消息的尾部。
44 | ///
45 | [Description("Trailer")]
46 | Trailer = 5,
47 |
48 | ///
49 | /// Transfer-Encoding 标头,指定对消息正文应用的转换的类型(如果有)。
50 | ///
51 | [Description("Transfer-Encoding")]
52 | TransferEncoding = 6,
53 |
54 | ///
55 | /// Upgrade 标头,指定客户端支持的附加通信协议。
56 | ///
57 | [Description("Upgrade")]
58 | Upgrade = 7,
59 |
60 | ///
61 | /// Via 标头,指定网关和代理程序要使用的中间协议。
62 | ///
63 | [Description("Via")]
64 | Via = 8,
65 |
66 | ///
67 | /// Warning 标头,指定关于可能未在消息中反映的消息的状态或转换的附加信息。
68 | ///
69 | [Description("Warning")]
70 | Warning = 9,
71 |
72 | ///
73 | /// Allow 标头,指定支持的 HTTP 方法集。
74 | ///
75 | [Description("Allow")]
76 | Allow = 10,
77 |
78 | ///
79 | /// Content-Length 标头,指定伴随正文数据的长度(以字节为单位)。
80 | ///
81 | [Description("Content-Length")]
82 | ContentLength = 11,
83 |
84 | ///
85 | /// Content-Type 标头,指定伴随正文数据的 MIME 类型。
86 | ///
87 | [Description("Content-Type")]
88 | ContentType = 12,
89 |
90 | ///
91 | /// Content-Encoding 标头,指定已应用于伴随正文数据的编码。
92 | ///
93 | [Description("Content-Encoding")]
94 | ContentEncoding = 13,
95 |
96 | ///
97 | /// Content-Langauge 标头,指定伴随正文数据的自然语言。
98 | ///
99 | [Description("Content-Langauge")]
100 | ContentLanguage = 14,
101 |
102 | ///
103 | /// Content-Location 标头,指定可从其中获得伴随正文的 URI。
104 | ///
105 | [Description("Content-Location")]
106 | ContentLocation = 15,
107 |
108 | ///
109 | /// Content-MD5 标头,指定伴随正文数据的 MD5 摘要,用于提供端到端消息完整性检查。
110 | ///
111 | [Description("Content-MD5")]
112 | ContentMd5 = 16,
113 |
114 | ///
115 | /// Content-Range 标头,指定在完整正文中应用伴随部分正文数据的位置。
116 | ///
117 | [Description("Content-Range")]
118 | ContentRange = 17,
119 |
120 | ///
121 | /// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。
122 | ///
123 | [Description("Expires")]
124 | Expires = 18,
125 |
126 | ///
127 | /// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。
128 | ///
129 | [Description("Last-Modified")]
130 | LastModified = 19,
131 |
132 | ///
133 | /// Accept 标头,指定响应可接受的 MIME 类型。
134 | ///
135 | [Description("Accept")]
136 | Accept = 20,
137 |
138 | ///
139 | /// Accept-Charset 标头,指定响应可接受的字符集。
140 | ///
141 | [Description("Accept-Charset")]
142 | AcceptCharset = 21,
143 |
144 | ///
145 | /// Accept-Encoding 标头,指定响应可接受的内容编码。
146 | ///
147 | [Description("Accept-Encoding")]
148 | AcceptEncoding = 22,
149 |
150 | ///
151 | /// Accept-Langauge 标头,指定响应首选的自然语言。
152 | ///
153 | [Description("Accept-Langauge")]
154 | AcceptLanguage = 23,
155 |
156 | ///
157 | /// Authorization 标头,指定客户端为向服务器验证自身身份而出示的凭据。
158 | ///
159 | [Description("Authorization")]
160 | Authorization = 24,
161 |
162 | ///
163 | /// Cookie 标头,指定向服务器提供的 Cookie 数据。
164 | ///
165 | [Description("Cookie")]
166 | Cookie = 25,
167 |
168 | ///
169 | /// Expect 标头,指定客户端要求的特定服务器行为。
170 | ///
171 | [Description("Expect")]
172 | Expect = 26,
173 |
174 | ///
175 | /// From 标头,指定控制请求用户代理的用户的 Internet 电子邮件地址。
176 | ///
177 | [Description("From")]
178 | From = 27,
179 |
180 | ///
181 | /// Host 标头,指定所请求资源的主机名和端口号。
182 | ///
183 | [Description("Host")]
184 | Host = 28,
185 |
186 | ///
187 | /// If-Match 标头,指定仅当客户端的指示资源的缓存副本是最新的时,才执行请求的操作。
188 | ///
189 | [Description("If-Match")]
190 | IfMatch = 29,
191 |
192 | ///
193 | /// If-Modified-Since 标头,指定仅当自指示的数据和时间之后修改了请求的资源时,才执行请求的操作。
194 | ///
195 | [Description("If-Modified-Since")]
196 | IfModifiedSince = 30,
197 |
198 | ///
199 | /// If-None-Match 标头,指定仅当客户端的指示资源的缓存副本都不是最新的时,才执行请求的操作。
200 | ///
201 | [Description("If-None-Match")]
202 | IfNoneMatch = 31,
203 |
204 | ///
205 | /// If-Range 标头,指定如果客户端的缓存副本是最新的,仅发送指定范围的请求资源。
206 | ///
207 | [Description("If-Range")]
208 | IfRange = 32,
209 |
210 | ///
211 | /// If-Unmodified-Since 标头,指定仅当自指示的日期和时间之后修改了请求的资源时,才执行请求的操作。
212 | ///
213 | [Description("If-Unmodified-Since")]
214 | IfUnmodifiedSince = 33,
215 |
216 | ///
217 | /// Max-Forwards 标头,指定一个整数,表示此请求还可转发的次数。
218 | ///
219 | [Description("Max-Forwards")]
220 | MaxForwards = 34,
221 |
222 | ///
223 | /// Proxy-Authorization 标头,指定客户端为向代理验证自身身份而出示的凭据。
224 | ///
225 | [Description("Proxy-Authorization")]
226 | ProxyAuthorization = 35,
227 |
228 | ///
229 | /// Referer 标头,指定从中获得请求 URI 的资源的 URI。
230 | ///
231 | [Description("Referer")]
232 | Referer = 36,
233 |
234 | ///
235 | /// Range 标头,指定代替整个响应返回的客户端请求的响应的子范围。
236 | ///
237 | [Description("Range")]
238 | Range = 37,
239 |
240 | ///
241 | /// TE 标头,指定响应可接受的传输编码方式。
242 | ///
243 | [Description("TE")]
244 | Te = 38,
245 |
246 | ///
247 | /// Translate 标头,与 WebDAV 功能一起使用的 HTTP 规范的 Microsoft 扩展。
248 | ///
249 | [Description("Translate")]
250 | Translate = 39,
251 |
252 | ///
253 | /// User-Agent 标头,指定有关客户端代理的信息。
254 | ///
255 | [Description("User-Agent")]
256 | UserAgent = 40,
257 |
258 |
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/ResponseHeaders.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace HTTPServerLib
9 | {
10 | public enum ResponseHeaders
11 | {
12 | ///
13 | /// Cache-Control 标头,指定请求/响应链上所有缓存机制必须服从的缓存指令。
14 | ///
15 | [Description("Cache-Control")]
16 | CacheControl = 0,
17 |
18 | ///
19 | /// Connection 标头,指定特定连接需要的选项。
20 | ///
21 | [Description("Connection")]
22 | Connection = 1,
23 |
24 | ///
25 | /// Date 标头,指定响应产生的日期和时间。
26 | ///
27 | [Description("Date")]
28 | Date = 2,
29 |
30 | ///
31 | /// Keep-Alive 标头,指定用于维护持久连接的参数。
32 | ///
33 | [Description("Keep-Alive")]
34 | KeepAlive = 3,
35 |
36 | ///
37 | /// Pragma 标头,指定可应用于请求/响应链上的任何代理的特定于实现的指令。
38 | ///
39 | [Description("Pragma")]
40 | Pragma = 4,
41 |
42 | ///
43 | /// Trailer 标头,指定指示的标头字段在消息(使用分块传输编码方法进行编码)的尾部显示。
44 | ///
45 | [Description("Trailer")]
46 | Trailer = 5,
47 |
48 | ///
49 | /// Transfer-Encoding 标头,指定对消息正文应用哪种类型的转换(如果有)。
50 | ///
51 | [Description("Transfer-Encoding")]
52 | TransferEncoding = 6,
53 |
54 | ///
55 | /// Upgrade 标头,指定客户端支持的附加通信协议。
56 | ///
57 | [Description("Upgrade")]
58 | Upgrade = 7,
59 |
60 | ///
61 | /// Via 标头,指定网关和代理程序要使用的中间协议。
62 | ///
63 | [Description("Via")]
64 | Via = 8,
65 |
66 | ///
67 | /// Warning 标头,指定关于可能未在消息中反映的消息的状态或转换的附加信息。
68 | ///
69 | [Description("Warning")]
70 | Warning = 9,
71 |
72 | ///
73 | /// Allow 标头,指定支持的 HTTP 方法集。
74 | ///
75 | [Description("Allow")]
76 | Allow = 10,
77 |
78 | ///
79 | /// Content-Length 标头,指定伴随正文数据的长度(以字节为单位)。
80 | ///
81 | [Description("Content-Length")]
82 | ContentLength = 11,
83 |
84 | ///
85 | /// Content-Type 标头,指定伴随正文数据的 MIME 类型。
86 | ///
87 | [Description("Content-Type")]
88 | ContentType = 12,
89 |
90 | ///
91 | /// Content-Encoding 标头,指定已应用于伴随正文数据的编码。
92 | ///
93 | [Description("Content-Encoding")]
94 | ContentEncoding = 13,
95 |
96 | ///
97 | /// Content-Langauge 标头,指定自然语言或伴随正文数据的语言。
98 | ///
99 | [Description("Content-Langauge")]
100 | ContentLanguage = 14,
101 |
102 | ///
103 | /// Content-Location 标头,指定可以从中获取伴随正文的 URI。
104 | ///
105 | [Description("Content-Location")]
106 | ContentLocation = 15,
107 |
108 | ///
109 | /// Content-MD5 标头,指定伴随正文数据的 MD5 摘要,用于提供端到端消息完整性检查。
110 | ///
111 | [Description("Content-MD5")]
112 | ContentMd5 = 16,
113 |
114 | ///
115 | /// Range 标头,指定客户端请求返回的响应的单个或多个子范围来代替整个响应。
116 | ///
117 | [Description("Range")]
118 | ContentRange = 17,
119 |
120 | ///
121 | /// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。
122 | ///
123 | [Description("Expires")]
124 | Expires = 18,
125 |
126 | ///
127 | /// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。
128 | ///
129 | [Description("Last-Modified")]
130 | LastModified = 19,
131 |
132 | ///
133 | /// Accept-Ranges 标头,指定服务器接受的范围。
134 | ///
135 | [Description("Accept-Ranges")]
136 | AcceptRanges = 20,
137 |
138 | ///
139 | /// Age 标头,指定自起始服务器生成响应以来的时间长度(以秒为单位)。
140 | ///
141 | [Description("Age")]
142 | Age = 21,
143 |
144 | ///
145 | /// Etag 标头,指定请求的变量的当前值。
146 | ///
147 | [Description("Etag")]
148 | ETag = 22,
149 |
150 | ///
151 | /// Location 标头,指定为获取请求的资源而将客户端重定向到的 URI。
152 | ///
153 | [Description("Location")]
154 | Location = 23,
155 |
156 | ///
157 | /// Proxy-Authenticate 标头,指定客户端必须对代理验证其自身。
158 | ///
159 | [Description("Proxy-Authenticate")]
160 | ProxyAuthenticate = 24,
161 |
162 | ///
163 | /// Retry-After 标头,指定某个时间(以秒为单位)或日期和时间,在此时间之后客户端可以重试其请求。
164 | ///
165 | [Description("Retry-After")]
166 | RetryAfter = 25,
167 |
168 | ///
169 | /// Server 标头,指定关于起始服务器代理的信息。
170 | ///
171 | [Description("Server")]
172 | Server = 26,
173 |
174 | ///
175 | /// Set-Cookie 标头,指定提供给客户端的 Cookie 数据。
176 | ///
177 | [Description("Set-Cookie")]
178 | SetCookie = 27,
179 |
180 | ///
181 | /// Vary 标头,指定用于确定缓存的响应是否为新响应的请求标头。
182 | ///
183 | [Description("Vary")]
184 | Vary = 28,
185 |
186 | ///
187 | /// WWW-Authenticate 标头,指定客户端必须对服务器验证其自身。
188 | ///
189 | [Description("WWW-Authenticate")]
190 | WwwAuthenticate = 29,
191 |
192 |
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/ResponseHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.IO;
7 | using System.Runtime.InteropServices;
8 |
9 | namespace HTTPServerLib
10 | {
11 | public static class ResponseHelper
12 | {
13 | public static HttpResponse FromFile(this HttpResponse response, string fileName)
14 | {
15 | if (!File.Exists(fileName))
16 | {
17 | response.SetContent("404 - Not Found
");
18 | response.StatusCode = "404";
19 | response.Content_Type = "text/html";
20 | return response;
21 | }
22 |
23 | var content = File.ReadAllBytes(fileName);
24 | var contentType = GetMimeFromFile(fileName);
25 | response.SetContent(content);
26 | response.Content_Type = contentType;
27 | response.StatusCode = "200";
28 | return response;
29 | }
30 |
31 | public static HttpResponse FromXML(this HttpResponse response, string xmlText)
32 | {
33 | response.SetContent(xmlText);
34 | response.Content_Type = "text/xml";
35 | response.StatusCode = "200";
36 | return response;
37 | }
38 |
39 | public static HttpResponse FromXML(this HttpResponse response, T entity) where T : class
40 | {
41 | return response.FromXML("");
42 | }
43 |
44 | public static HttpResponse FromJSON(this HttpResponse response, string jsonText)
45 | {
46 | response.SetContent(jsonText);
47 | response.Content_Type = "text/json";
48 | response.StatusCode = "200";
49 | return response;
50 | }
51 |
52 | public static HttpResponse FromJSON(this HttpResponse response, T entity) where T : class
53 | {
54 | return response.FromJSON("");
55 | }
56 |
57 | public static HttpResponse FromText(this HttpResponse response, string text)
58 | {
59 | response.SetContent(text);
60 | response.Content_Type = "text/plain";
61 | response.StatusCode = "200";
62 | return response;
63 | }
64 |
65 | private static string GetMimeFromFile(string filePath)
66 | {
67 | IntPtr mimeout;
68 | if (!File.Exists(filePath))
69 | throw new FileNotFoundException(string.Format("File {0} can't be found at server.", filePath));
70 |
71 | int MaxContent = (int)new FileInfo(filePath).Length;
72 | if (MaxContent > 4096) MaxContent = 4096;
73 | byte[] buf = new byte[MaxContent];
74 |
75 | using (FileStream fs = File.OpenRead(filePath))
76 | {
77 | fs.Read(buf, 0, MaxContent);
78 | fs.Close();
79 | }
80 |
81 | int result = FindMimeFromData(IntPtr.Zero, filePath, buf, MaxContent, null, 0, out mimeout, 0);
82 | if (result != 0)
83 | throw Marshal.GetExceptionForHR(result);
84 |
85 | string mime = Marshal.PtrToStringUni(mimeout);
86 | Marshal.FreeCoTaskMem(mimeout);
87 |
88 | return mime;
89 | }
90 |
91 | [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
92 | static extern int FindMimeFromData(IntPtr pBC,
93 | [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
94 | [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeParamIndex = 3)]
95 | byte[] pBuffer,
96 | int cbSize,
97 | [MarshalAs(UnmanagedType.LPWStr)]
98 | string pwzMimeProposed,
99 | int dwMimeFlags,
100 | out IntPtr ppwzMimeOut,
101 | int dwReserved);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/RouteAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | [AttributeUsage(AttributeTargets.Method)]
10 | class RouteAttribute:Attribute
11 | {
12 | public RouteMethod Method { get; set; }
13 | public string RoutePath { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/RouteMethod.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public enum RouteMethod
10 | {
11 | Get,
12 | Post
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/ServiceModule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Reflection;
7 |
8 | namespace HTTPServerLib
9 | {
10 | public class ServiceModule
11 | {
12 | public bool SearchRoute(ServiceRoute route)
13 | {
14 | return true;
15 | }
16 |
17 | public ActionResult ExecuteRoute(ServiceRoute route)
18 | {
19 | var type = this.GetType();
20 | var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
21 | methods = methods.Where(m => m.ReturnType == typeof(ActionResult)).ToArray();
22 | if (methods == null || methods.Length <= 0) return null;
23 | var method = methods.FirstOrDefault(m =>
24 | {
25 | var attribute = m.GetCustomAttribute(true);
26 | if (attribute == null) return false;
27 | if (attribute.Method == route.Method && attribute.RoutePath == route.RoutePath)
28 | return true;
29 | return false;
30 | });
31 |
32 | if (method == null) return null;
33 | return (ActionResult)method.Invoke(this, new object[] { });
34 |
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/HTTPServer/HTTPServerLib/ServiceRoute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace HTTPServerLib
8 | {
9 | public class ServiceRoute
10 | {
11 | public RouteMethod Method { get; private set; }
12 | public string RoutePath { get; private set; }
13 |
14 | public static ServiceRoute Parse(HttpRequest request)
15 | {
16 | var route = new ServiceRoute();
17 | route.Method = (RouteMethod)Enum.Parse(typeof(RouteMethod), request.Method);
18 | route.RoutePath = request.URL;
19 | return route;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/HTTPServer/Packages.dgml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/HTTPServer/Packages/LitJson.0.7.0/LitJson.0.7.0.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qinyuanpei/HttpServer/f5decb7b887b3afe1b9ec55b29b8a73112851bbd/HTTPServer/Packages/LitJson.0.7.0/LitJson.0.7.0.nupkg
--------------------------------------------------------------------------------
/HTTPServer/Packages/LitJson.0.7.0/lib/LitJson.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qinyuanpei/HttpServer/f5decb7b887b3afe1b9ec55b29b8a73112851bbd/HTTPServer/Packages/LitJson.0.7.0/lib/LitJson.dll
--------------------------------------------------------------------------------
/HTTPServer/Packages/repositories.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HttpServer
2 | [](https://www.travis-ci.org/qinyuanpei/HttpServer)
3 | 
4 |
5 | 一个使用C#编写的简易Web服务器, 目前支持:
6 | * 静态页面处理 :smile:
7 | * GET/POST请求 :smile:
8 | * 支持HTTPS协议 :smile:
9 | * 支持返回JSON :worried:
10 | * 支持路由方法 :worried:
11 |
12 | # 快速开始
13 |
14 | ## HTTP服务器示例
15 | ```
16 | class Program
17 | {
18 | static void Main(string[] args)
19 | {
20 | ExampleServer server = new ExampleServer("0.0.0.0",4050);
21 | server.Start();
22 | }
23 | }
24 | ```
25 |
26 | ## GET/POST请求示例
27 | ```
28 | public override void OnPost(HttpRequest request, HttpResponse response)
29 | {
30 | //获取客户端传递的参数
31 | string data = request.Params == null ? "" : string.Join(";", request.Params.Select(x => x.Key + "=" + x.Value).ToArray());
32 |
33 | //设置返回信息
34 | string content = string.Format("这是通过Post方式返回的数据:{0}", data);
35 |
36 | //构造响应报文
37 | response.SetContent(content);
38 | response.Content_Encoding = "utf-8";
39 | response.StatusCode = "200";
40 | response.Content_Type = "text/html; charset=UTF-8";
41 | response.Server = "ExampleServer";
42 |
43 | //发送响应
44 | response.Send();
45 | }
46 |
47 | public override void OnGet(HttpRequest request, HttpResponse response)
48 | {
49 |
50 | ///链接形式1:"http://localhost:4050/assets/styles/style.css"表示访问指定文件资源,
51 | ///此时读取服务器目录下的/assets/styles/style.css文件。
52 |
53 | ///链接形式1:"http://localhost:4050/assets/styles/"表示访问指定页面资源,
54 | ///此时读取服务器目录下的/assets/styles/style.index文件。
55 |
56 | //当文件不存在时应返回404状态码
57 | string requestURL = request.URL;
58 | requestURL = requestURL.Replace("/", @"\").Replace("\\..", "").TrimStart('\\');
59 | string requestFile = Path.Combine(ServerRoot, requestURL);
60 |
61 | //判断地址中是否存在扩展名
62 | string extension = Path.GetExtension(requestFile);
63 |
64 | //根据有无扩展名按照两种不同链接进行处
65 | if (extension != "")
66 | {
67 | //从文件中返回HTTP响应
68 | response = LoadFromFile(response, requestFile);
69 | }
70 | else
71 | {
72 | //目录存在且不存在index页面时时列举目录
73 | if (Directory.Exists(requestFile) && !File.Exists(requestFile + "\\index.html"))
74 | {
75 | requestFile = Path.Combine(ServerRoot, requestFile);
76 | var content = ListDirectory(requestFile, requestURL);
77 | response = response.SetContent(content, Encoding.UTF8);
78 | response.Content_Type = "text/html; charset=UTF-8";
79 | }
80 | else
81 | {
82 | //加载静态HTML页面
83 | requestFile = Path.Combine(requestFile, "index.html");
84 | response = LoadFromFile(response, requestFile);
85 | response.Content_Type = "text/html; charset=UTF-8";
86 | }
87 | }
88 |
89 | //发送HTTP响应
90 | response.Send();
91 | }
92 | ```
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | # must be unique in a given SonarQube instance
2 | sonar.projectKey=Sonar-HttpServer
3 | # this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
4 | sonar.projectName=HttpServer
5 | sonar.projectVersion=1.0
6 |
7 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
8 | # This property is optional if sonar.modules is set.
9 | sonar.sources=.
10 |
11 | # Encoding of the source code. Default is default system encoding
12 | #sonar.sourceEncoding=UTF-8
--------------------------------------------------------------------------------