This problem set guides you through building a basic HTTP server from scratch using Node.js's http module. The goal is to create a server that handles simple GET requests, parses incoming HTTP requests, and sends valid HTTP responses. We'll break it down into "tickets" – small, incremental tasks that build upon each other, simulating a real-world project workflow.
Prerequisites:
- Basic JavaScript knowledge (Node.js, objects, file system operations).
- No external libraries are allowed; use Node.js's built-in modules (e.g.,
http,fs,url). - Test your server using tools like
curl(e.g.,curl http://localhost:8080/) or a web browser.
Project Structure:
- Create a single JavaScript file, e.g.,
simple_http_server.js. - The server should run on
localhostport 8080 by default. - Handle only GET requests; respond with 405 Method Not Allowed for others.
- Serve static files from a
wwwdirectory in the same folder as your script (create it and add some HTML files for testing).
Running the Server:
- Run your script:
node simple_http_server.js. - It should listen indefinitely until interrupted (e.g., Ctrl+C).
Complete the tickets in order, testing each step before proceeding.
Description: Create the foundation for your HTTP server using Node.js's http module to listen for incoming requests.
Tasks:
- Import the
httpmodule. - Create an HTTP server using
http.createServer. - Make it listen on
localhost:8080. - For now, respond to every request with a simple
200 OKstatus and the body"Hello, World!". - Log a message like "Server is listening on port 8080..." when starting.
Testing:
- Run the script and use
curl http://localhost:8080or a browser. You should see "Hello, World!". - Ensure the server handles multiple requests without crashing.
Hints:
- Use
res.write()andres.end()to send responses. - Handle server errors (e.g., port in use) gracefully.
Description: Parse the HTTP request to extract the method and path, and validate that the method is GET.
Tasks:
- Access the request's
methodandurlproperties. - If the method is not "GET", respond with
405 Method Not Allowed. - For GET requests, continue responding with
"Hello, World!". - Log the method and URL of each request to the console.
- Handle malformed URLs (e.g., invalid format) with a
400 Bad Request.
Testing:
curl -X GET http://localhost:8080/→ "Hello, World!".curl -X POST http://localhost:8080/→ 405 response.- Check console logs for method and URL.
Hints:
- Use
req.methodandreq.url. - Set status with
res.statusCodeand headers withres.setHeader.
Description: Parse the HTTP headers from the request and store them for later use.
Tasks:
- Access headers via
req.headersand log them to the console. - Ensure headers are processed (though no specific action is needed yet).
- Continue with the existing responses (405 for non-GET, 200 for GET).
- Handle cases where headers are missing or malformed (respond with 400 if necessary).
Testing:
- Use
curl -v -H "X-Test: value" http://localhost:8080/to see headers logged. - Ensure non-GET requests still return 405.
Hints:
req.headersis an object; log it directly.- Check for invalid header formats if applicable.
Description: Implement basic routing for GET requests with proper HTTP response headers.
Tasks:
- For path
/, respond with200 OK,Content-Type: text/plain, and body"Hello, World!". - For path
/echo, respond with the request's method, URL, and headers as a JSON string. - For other paths, respond with
404 Not Foundand body"Not Found". - Include
Content-Lengthin all responses. - Ensure
\r\nline endings in headers.
Testing:
curl http://localhost:8080/→ "Hello, World!".curl http://localhost:8080/echo→ JSON with request details.curl http://localhost:8080/invalid→ 404 with "Not Found".
Hints:
- Use
JSON.stringifyfor/echo. - Calculate
Content-Lengthbased on the response body.
Description: Serve files from a www directory for GET requests.
Tasks:
- Create a
wwwfolder with anindex.htmlcontaining<h1>Welcome!</h1>. - Map
/towww/index.htmland other paths (e.g.,/style.css) towww/style.css. - Use
fsmodule to read files. - Set
Content-Typebased on file extension (.html→text/html,.css→text/css,.txt→text/plain, defaultapplication/octet-stream). - Prevent directory traversal (e.g.,
/../) by normalizing paths. - Respond with 404 if the file doesn't exist.
Testing:
curl http://localhost:8080/→ HTML content.curl http://localhost:8080/test.txt→ Text content.curl http://localhost:8080/missing→ 404.curl http://localhost:8080/../secret→ 400 or 404.
Hints:
- Use
pathmodule for safe path handling. - Read files with
fs.readFile.
Description: Enhance the server with robust error handling and detailed logging.
Tasks:
- Handle errors (e.g., file read errors, invalid requests) gracefully.
- Log each request with method, path, and status code (e.g.,
GET / 200). - Add a
Server: SimpleNodeServerheader to all responses. - Ensure the server doesn't crash on errors.
Testing:
- Simulate errors (e.g., remove
www/index.html, send invalid requests). - Check console logs for request details and errors.
Hints:
- Use try-catch for file operations.
- Use
console.errorfor error logging.
Description: Parse query parameters and include them in the /echo route.
Tasks:
- Use the
urlmodule to parse the request URL and extract query parameters. - For
/echo, include query parameters in the JSON response. - Ensure file serving uses the base path (ignoring query parameters).
- Handle invalid query strings gracefully.
Testing:
curl http://localhost:8080/echo?name=test→ JSON includes{"name": "test"}.curl http://localhost:8080/?param=value→ Servesindex.html.
Hints:
- Use
url.parse(req.url, true).queryfor query parameters. - Update
/echoto include query data.
Description: (Optional) Add a dynamic route /greet/:name that returns a personalized greeting.
Tasks:
- For paths like
/greet/Alice, respond with200 OKand body"Hello, Alice!". - Extract the
nameparameter from the path. - Return 404 for invalid dynamic routes.
- Maintain all previous functionality.
Testing:
curl http://localhost:8080/greet/Alice→ "Hello, Alice!".curl http://localhost:8080/greet/→ 404.
Hints:
- Split the path to extract parameters.
- Validate the route format.
Completing all tickets will result in a functional HTTP server in Node.js! This project teaches HTTP protocols, request parsing, and file serving. Extend it further if desired (e.g., support HEAD requests or use streams for large files). Submit your code and test outputs for review. Great job!