Skip to content

Commit

Permalink
Added Http server
Browse files Browse the repository at this point in the history
  • Loading branch information
mathanraj0601 committed May 30, 2024
0 parents commit 950d86f
Show file tree
Hide file tree
Showing 12 changed files with 901 additions and 0 deletions.
484 changes: 484 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions InnoSetup/innosetup.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "Web Server"
#define MyAppVersion "1.0.0"
#define MyAppPublisher "MR"
#define MyAppURL "MR"
#define MyAppExeName "WebServer.exe"
#define MyAppAssocName MyAppName + ""
#define MyAppAssocExt ".myp"
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt

[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{B148CD9D-BD2A-4634-9BB6-26A21BAD6515}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
ChangesAssociations=yes
DisableProgramGroupPage=yes
; Remove the following line to run in administrative install mode (install for all users.)
PrivilegesRequired=lowest
OutputDir=D:\Github learning\WebServer\Setup
OutputBaseFilename=setup
SetupIconFile=C:\Users\madha\Downloads\cloud-server.ico
Compression=lzma
SolidCompression=yes
WizardStyle=modern

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "D:\Github learning\WebServer\WebServer\bin\Release\net6.0\publish\win-x64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "D:\Github learning\WebServer\WebServer\bin\Release\net6.0\publish\win-x64\WebServer.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "D:\Github learning\WebServer\WebServer\bin\Release\net6.0\publish\win-x64\WebServer.pdb"; DestDir: "{app}"; Flags: ignoreversion
Source: "D:\Github learning\WebServer\WebServer\bin\Release\net6.0\publish\win-x64\wwwroot\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Registry]
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\{#MyAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".myp"; ValueData: ""

[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

Binary file added Setup/WebServerSetup.exe
Binary file not shown.
25 changes: 25 additions & 0 deletions WebServer.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34622.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebServer", "WebServer\WebServer.csproj", "{0B8E1EBD-0B65-4223-96C2-63273934FE73}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0B8E1EBD-0B65-4223-96C2-63273934FE73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B8E1EBD-0B65-4223-96C2-63273934FE73}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B8E1EBD-0B65-4223-96C2-63273934FE73}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B8E1EBD-0B65-4223-96C2-63273934FE73}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9E7122E1-8DE8-40A0-9CF9-A34BBB694F82}
EndGlobalSection
EndGlobal
168 changes: 168 additions & 0 deletions WebServer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace WebServer
{
public class Program
{

// Default file location
static string _webRootUrl = $"wwwroot\\";

// Default port
static int port = 12345;
static void Main(string[] args)
{

if (_webRootUrl == null || _webRootUrl == String.Empty)
{
Console.WriteLine("No path is provided");
return;
}


if(args.Length >= 1)
_webRootUrl = args[0];
if (args.Length >=2)
port = int.Parse(args[1]);

TcpListener server = new TcpListener(IPAddress.Any, port);
server.Start();
Console.WriteLine($"Server started on {port}");

while (true)
{
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Client connected!");
ThreadPool.SetMaxThreads(10, 10);
ThreadPool.QueueUserWorkItem(new WaitCallback(Respond), client);

// UN managed thread result in exhaustion
//Thread thread = new Thread(() => Respond(client));
//thread.Start();

}


}

static async void Respond(Object? clientObject)
{
if (clientObject is not TcpClient) {
return;
}

TcpClient client = (TcpClient)clientObject;

try
{
// 30 secs timout for send and receive
client.SendTimeout = 3000;
client.ReceiveTimeout = 3000;
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
string requestData = Encoding.ASCII.GetString(buffer, 0, bytesRead);

string[] requestParts = requestData.Split(' '); // Split the request line into its parts

if (requestData.Length < 2)
{
string badRequest = "HTTP/1.1 400 Bad request\r\n\r\n";
byte[] badRequestBytes = Encoding.ASCII.GetBytes(badRequest);
await stream.WriteAsync(badRequestBytes, 0, badRequestBytes.Length);
return;
}

string method = requestParts[0]; // HTTP method (e.g., GET, POST)
string url = requestParts[1]; // Request URL


if (method == "GET")
{
// Extracting file path
string filePath = string.Empty;
if (url == "/")
url = "/index.html";
filePath = $"{_webRootUrl}{url.Substring(1, url.Length - 1)}";


if (File.Exists(filePath))
{
byte[] html = await File.ReadAllBytesAsync(filePath);
string type = getType(url);

string responseData = "HTTP/1.1 200 OK\r\n" +
"Content-Type: " + type + "\r\n" +
"Content-Length: " + html.Length + "\r\n\r\n";

// Header
byte[] responseHeaderBytes = Encoding.ASCII.GetBytes(responseData);

// Reponse object
byte[] responseBytes = new byte[responseHeaderBytes.Length + html.Length];

// Copying response header to reponse object
Buffer.BlockCopy(responseHeaderBytes, 0, responseBytes, 0, responseHeaderBytes.Length);

// Copying actual content to response object
Buffer.BlockCopy(html, 0, responseBytes, responseHeaderBytes.Length, html.Length);

stream.Write(responseBytes, 0, responseBytes.Length);

return;
}

}
string notFoundResponse = "HTTP/1.1 404 Not Found\r\n\r\n";
byte[] notFoundResponseBytes = Encoding.ASCII.GetBytes(notFoundResponse);
await stream.WriteAsync(notFoundResponseBytes, 0, notFoundResponseBytes.Length);
}
catch(Exception ex)
{
if (ex is SocketException && (ex as SocketException)?.SocketErrorCode == SocketError.TimedOut)
{

Console.WriteLine("Operation timed out. "+ ex.Message);

}
else
{
Console.WriteLine("Error: " + ex.Message);
}
}
finally
{
client.Close();
}
}


static string getType(string url)
{
if (url.EndsWith("html"))
return "text/html";
if (url.EndsWith("css"))
return "text/css";
if (url.EndsWith("js"))
return "text/javascript";
if (url.EndsWith(".jpg") || url.EndsWith(".jpeg"))
return "image/jpeg";
if (url.EndsWith(".png"))
return "image/png";
if (url.EndsWith(".gif"))
return "image/gif";
if (url.EndsWith(".svg"))
return "image/svg+xml";
if (url.EndsWith(".ico"))
return "image/x-icon";
else
return "text/plain";
}

}


}

7 changes: 7 additions & 0 deletions WebServer/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"profiles": {
"WebServer": {
"commandName": "Project"
}
}
}
34 changes: 34 additions & 0 deletions WebServer/WebServer.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ApplicationIcon>cloud-server.ico</ApplicationIcon>
</PropertyGroup>

<ItemGroup>
<None Remove="wwwroot\favicon.ico" />
<None Remove="wwwroot\index.html" />
<None Remove="wwwroot\script.js" />
<None Remove="wwwroot\style.css" />
</ItemGroup>

<ItemGroup>
<Content Include="cloud-server.ico" />
<Content Include="wwwroot\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="wwwroot\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="wwwroot\script.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="wwwroot\style.css">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>

</Project>
Binary file added WebServer/cloud-server.ico
Binary file not shown.
Binary file added WebServer/wwwroot/favicon.ico
Binary file not shown.
33 changes: 33 additions & 0 deletions WebServer/wwwroot/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple HTTP Web Server</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Welcome to my Simple HTTP Web Server!</h1>
<p>Get started exploring the world of web servers.</p>
<div class="button-container">
<button class="button documentation">Documentation</button>
<button class="button how-to-use">How to Use</button>
</div>
<div id="content">
<div id="documentation" class="content-section">
<h2>Documentation</h2>
<p>Click <a href="#">here</a> for documentation.</p>
</div>
<div id="how-to-use" class="content-section hidden">
<h2>How to Use</h2>
<p>Click <a href="#">here</a> for How to use.</p>
</div>
</div>
<i class="notes">The webserver by default listen in 12345 port</i>

</div>

<script src="script.js"></script>
</body>
</html>
14 changes: 14 additions & 0 deletions WebServer/wwwroot/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const buttons = document.querySelectorAll('.button');
const contentSections = document.querySelectorAll('.content-section');

buttons.forEach(button => {
button.addEventListener('click', () => {
const contentId = button.classList.contains('documentation') ? 'documentation' : 'how-to-use';
contentSections.forEach(section => {
section.classList.remove('active'); // Deactivate all content sections
if (section.id === contentId) {
section.classList.add('active'); // Activate the clicked button's content section
}
});
});
});
Loading

0 comments on commit 950d86f

Please sign in to comment.