diff --git a/lib/parser.js b/lib/parser.js index 5efd3ed..d9333a1 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -1,181 +1,126 @@ -const request = require('../test/test.js') -const net = require('net') +const net = require("net"); +const testRequest = require("../test/test.js"); -// net.createServer((socket)=>{ -// socket.on('data',(data)=>{ -// console.log(data) -// const buff = data.toString() -// console.log(buff) -// httpParser(buff) -// }) -// }).listen(8080,()=>{ -// console.log("server started") -// -// }) - -function findFirstBrac (req, target) { +// Helper function to find the position of the first occurrence of a target character +function findFirstBrac(req, target) { for (let i = 0; i < req.length; i++) { - if (req[i] === target) { - return i // Return the position of the target character + if (req[i] === target) { + return i; // Return the position of the target character } } - return -1 + return -1; // Return -1 if target character is not found } -// POST /api/users HTTP/1.1 -async function httpParser (request) { - const req = new Object() - const requestString = request.split('\n') - const pos = findFirstBrac(requestString, '{') - const requestWoBody = requestString.slice(0, pos) - // console.log(requestWoBody) - req.method = requestWoBody[0].split(' ')[0] - req.path = requestString[0].split(' ')[1] - req.version = requestString[0].split(' ')[2] - if (req.method == 'GET') { - return req - } - HTTPbody(requestString, pos) - .then((data) => { - req.body = JSONbodyParser(data) - }) - - // console.log(requestString) - // console.log(req) - return req -} -// httpParser("POST /api/users HTTP/1.1 \nhost:www.google.com") -// console.time('Execution Time'); -// JSONbodyParser("{key:value,loda:lassan,}") -// console.time() -httpParser(request).then((data) => { - -}) - -function storePair (req, httpJSON) { - let key = '' - let i = 0 - while (req[i] != ':') { - key += req[i] - req.shift() - // console.log(req) - } - req.shift() - let value = '' - i = 0 - // console.log(req) - while (req[i] != ',') { - if (req[i] == null) { - break +// Parse HTTP body (handles asynchronous parsing and rejects on error) +async function HTTPbody(req, pos) { + let body = ""; + return new Promise((resolve, reject) => { + let flag = 0; + try { + for (let i = pos; i < req.length; i++) { + if (req[i] === "{") { + flag++; + } else if (req[i] === "}") { + flag--; + } + body += req[i]; + if (flag === 0 && req[i] === "}") break; // Stop once the body has been fully captured + } + resolve(body.replace(/\s+/g, "").replace(/"/g, "")); // Clean up the body + } catch (error) { + reject(`Error parsing HTTP body: ${error.message}`); } - value += req[i] - req.shift() - // console.log(req) - } - req.shift() - httpJSON[key] = value - // console.log(req) - // console.log("length"+req.length) - return req + }); } -function JSONbodyParser (body) { - const req = body.split('') - const httpJSON = new Object() - let flag = 0 - let pos = 0 - while (req.length != 0) { - if (req[0] == '{') { - flag += 1 - pos += 1 - req.shift() - } else if (req[0] == '}') { - flag -= 1 - pos += 1 - req.shift() +// Parse JSON body +function JSONbodyParser(body) { + const req = body.split(""); + const httpJSON = {}; + while (req.length !== 0) { + if (req[0] === "{" || req[0] === "}") { + req.shift(); // Skip braces } else { - // console.log(req) - storePair(req, httpJSON) - // console.log("i") + storePair(req, httpJSON); // Store key-value pair } } + return httpJSON; +} - // console.log(JSON.stringify(httpJSON)) - // console.timeEnd('Execution Time'); - return httpJSON +// Store a key-value pair from the request into the httpJSON object +function storePair(req, httpJSON) { + let key = ""; + while (req[0] !== ":") { + key += req.shift(); // Collect characters until colon + } + req.shift(); // Skip the colon + let value = ""; + while (req[0] !== "," && req[0] !== "}") { + value += req.shift(); // Collect value until comma or closing brace + } + if (req[0] === ",") req.shift(); // Skip the comma + httpJSON[key] = value; // Store key-value pair in JSON object } -function HTTPbody (req, pos) { - flag = 0 - let body = '' - return new Promise((resolve, reject) => { - const position = pos - for (let i = position; i < req.length; i++) { - if (req[i] == '{') { - flag++ - body += req[i] - } else if (req[i] == '}') { - flag-- - body += req[i] - } - body += req[i] +// Function to parse HTTP request headers and body +async function HTTPbody(req, pos) { + let body = ""; + let flag = 0; + + for (let i = pos; i < req.length; i++) { + if (req[i] === "{") { + flag++; + } else if (req[i] === "}") { + flag--; } - // console.log((body.replace(/\s+/g, '').replace(/"/g, ''))) remove all white spaces and quotes + body += req[i]; - resolve(body.replace(/\s+/g, '').replace(/"/g, '')) - }) -} + // Simulating an asynchronous operation with a delay for demonstration purposes + await new Promise((resolve) => setTimeout(resolve, 0)); // This simulates yielding control, allowing for asynchronous flow -function queryParser (request) { - const req = new Object() - const pos = findFirstBrac(request, '?') - const query = request.slice(0, pos) - while (req.length != 0) { - storeQuery(query) + if (flag === 0 && req[i] === "}") break; // Stop once the body has been fully captured } -} -function storeQuery (query) { - const req = query.split('') - const httpQueryJSON = new Object() - let flag = 0 - let pos = 0 - while (req.length != 0) { - if (req[0] == '{') { - flag += 1 - pos += 1 - req.shift() - } else if (req[0] == '}') { - flag -= 1 - pos += 1 - req.shift() - } else { - queryStorePair(req) - } - } - return httpQueryJSON + // Return cleaned-up body after parsing + return body.replace(/\s+/g, "").replace(/"/g, ""); // Clean up the body } -function queryStorePair (req) { - let key = '' - let i = 0 - while (req[i] != '=') { - key += req[i] - req.shift() - } - req.shift() - let value = '' - i = 0 - while (req[i] != '&') { - value += req[i] - req.shift() - } - req.shift() - httpQueryJSON[key] = value +// Query parsing function (parses query parameters from URL) +function queryParser(url) { + const req = {}; + const pos = findFirstBrac(url, "?"); + if (pos === -1) return req; // Return empty object if no query parameters + + const queryString = url.slice(pos + 1); // Slice starting after '?' + const queryParams = queryString.split("&"); - // console.log(req) - return httpQueryJSON + queryParams.forEach((param) => { + const [key, value] = param.split("="); + req[key] = value || ""; // Store key-value pair, handle empty values + }); + + return req; } -// storeQuery("key=value&loda=lassan") -queryParser('https//:fhdfjdh.com?key=value&loda=lassan') +// Example server using net module +net + .createServer((socket) => { + socket.on("data", (data) => { + const rawData = data.toString(); + httpParser(rawData) + .then((parsedRequest) => { + // Example of parsed request, uncomment to log it + // console.log(parsedRequest); + }) + .catch((err) => { + console.error("Error while parsing request:", err); + }); + }); + }) + .listen(8080, () => { + // Example of server startup message, uncomment to log it + // console.log("Server started on port 8080"); + }); + +// Example test case, uncomment to test query parsing +// console.log(queryParser("https://example.com?key=value&foo=bar")); diff --git a/lib/utils.js b/lib/utils.js index 1ab21fa..2c129e3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,171 +1,177 @@ -function findFirstBrac (req, target) { +function findFirstBrac(req, target) { for (let i = 0; i < req.length; i++) { if (req[i] === target) { - return i + return i; } } - return -1 + return -1; } -function HTTPbody (req, pos) { - let flag = 0 - let body = '' +function HTTPbody(req, pos) { + let flag = 0; + let body = ""; return new Promise((resolve, reject) => { - const position = pos + const position = pos; for (let i = position; i < req.length; i++) { - if (req[i] == '{') { - flag++ - body += req[i] - } else if (req[i] == '}') { - flag-- - body += req[i] + if (req[i] === "{") { + flag++; + body += req[i]; + } else if (req[i] === "}") { + flag--; + body += req[i]; } else { - body += req[i] + body += req[i]; } } // Simple whitespace cleanup - const cleanedBody = cleanUpBody(body) - resolve(cleanedBody) - }) + const cleanedBody = cleanUpBody(body); + resolve(cleanedBody); + }); } -function cleanUpBody (body) { +function cleanUpBody(body) { // Trim leading and trailing spaces - body = body.trim() + body = body.trim(); // Replace multiple spaces with a single space - body = body.split(/\s+/).join(' ') + body = body.split(/\s+/).join(" "); // Manually handle spaces around colons and commas - body = body.replace(/\s*:\s*/g, ':').replace(/\s*,\s*/g, ',') + body = body.replace(/\s*:\s*/g, ":").replace(/\s*,\s*/g, ","); - return body + return body; } -function JSONbodyParser (body) { - const req = body.split('') - const httpJSON = new Object() - let flag = 0 - const pos = 0 +function JSONbodyParser(body) { + const req = body.split(""); + const httpJSON = new Object(); + let flag = 0; + const pos = 0; // Check for empty input - if (req.length < 1) return httpJSON + if (req.length < 1) return httpJSON; while (req.length > 0) { - if (req[0] == '{') { - flag++ - req.shift() // Move past the '{' - } else if (req[0] == '}') { - flag-- - req.shift() // Move past the '}' + if (req[0] === "{") { + flag++; + req.shift(); // Move past the '{' + } else if (req[0] === "}") { + flag--; + req.shift(); // Move past the '}' } else { - storePair(req, httpJSON) + storePair(req, httpJSON); } } - return httpJSON + return httpJSON; } -function storePair (req, httpJSON) { - let key = '' - let value = '' +function storePair(req, httpJSON) { + let key = ""; + let value = ""; // Parse the key - while (req.length > 0 && req[0] !== ':') { - if (req[0] !== '"' && req[0] !== ' ') { - key += req[0] // Collect characters for the key + while (req.length > 0 && req[0] !== ":") { + if (req[0] !== '"' && req[0] !== " ") { + key += req[0]; // Collect characters for the key } - req.shift() // Move the pointer forward + req.shift(); // Move the pointer forward } - if (req.length < 1) return // Exit if we reach the end of input without finding a key-value pair - req.shift() // Skip over the colon ':' + if (req.length < 1) return; // Exit if we reach the end of input without finding a key-value pair + req.shift(); // Skip over the colon ':' // Parse the value - if (req.length > 0 && req[0] === '{') { - req.shift() // Remove the '{' - const nestedObject = {} - while (req.length > 0 && req[0] !== '}') { - storePair(req, nestedObject) // Store key-value pairs into the nested object + if (req.length > 0 && req[0] === "{") { + req.shift(); // Remove the '{' + const nestedObject = {}; + while (req.length > 0 && req[0] !== "}") { + storePair(req, nestedObject); // Store key-value pairs into the nested object } - req.shift() // Remove the closing '}' - httpJSON[key.trim()] = nestedObject // Assign the nested object to the parent + req.shift(); // Remove the closing '}' + httpJSON[key.trim()] = nestedObject; // Assign the nested object to the parent } else { // Handle primitive values (strings, numbers, etc.) - value = parseValue(req) - httpJSON[key.trim()] = value // Store the key-value pair + value = parseValue(req); + httpJSON[key.trim()] = value; // Store the key-value pair } - return req + // No return needed since httpJSON is modified by reference } // Helper function to parse primitive values (strings, numbers, etc.) -function parseValue (req) { - let value = '' - let isString = false +function parseValue(req) { + let value = ""; + let isString = false; // Check if the value starts with a quote if (req[0] === '"') { - isString = true - req.shift() // Remove the starting quote + isString = true; + req.shift(); // Remove the starting quote } - while (req.length > 0 && req[0] !== ',' && req[0] !== '}' && req[0] !== ']') { + while (req.length > 0 && req[0] !== "," && req[0] !== "}" && req[0] !== "]") { if (isString) { // For strings, accumulate characters until the closing quote if (req[0] === '"') { - req.shift() // Remove the closing quote - break // Exit the loop after closing quote + req.shift(); // Remove the closing quote + break; // Exit the loop after closing quote } else { - value += req[0] + value += req[0]; } } else { // For non-strings (numbers, etc.), accumulate characters directly - value += req[0] + value += req[0]; } - req.shift() // Move the pointer forward + req.shift(); // Move the pointer forward } - if (req[0] === ',') req.shift() // Skip the comma between pairs + if (req[0] === ",") req.shift(); // Skip the comma between pairs // Handle numbers (check if it's a valid number string) if (!isString && !isNaN(Number(value))) { - return Number(value) // Return as a number if it can be converted + return Number(value); // Return as a number if it can be converted } - return isString ? value.trim() : value.trim() // Return the value + return isString ? value.trim() : value.trim(); // Return the value } -function queryParser (request) { - const httpQueryJSON = new Object() - const queryStart = request.indexOf('?') +function queryParser(request) { + const httpQueryJSON = new Object(); + const queryStart = request.indexOf("?"); if (queryStart === -1) { - return httpQueryJSON + return httpQueryJSON; } - const queryString = request.slice(queryStart + 1).split('&') + const queryString = request.slice(queryStart + 1).split("&"); for (let i = 0; i < queryString.length; i++) { - const [key, value] = queryString[i].split('=') + const [key, value] = queryString[i].split("="); if (key) { - httpQueryJSON[key] = value || '' + httpQueryJSON[key] = value || ""; } } - return httpQueryJSON + return httpQueryJSON; } -const mimeDb = require('./mimeDb') // Adjust the path as needed +const mimeDb = require("./mimeDb"); // Adjust the path as needed -function lookupMimeType (extension) { - const mimeType = Object.keys(mimeDb).find(type => +function lookupMimeType(extension) { + const mimeType = Object.keys(mimeDb).find((type) => mimeDb[type].extensions.includes(extension) - ) - return mimeType || 'application/octet-stream' // Default type + ); + return mimeType || "application/octet-stream"; // Default type } // Example usage: -module.exports = { findFirstBrac, HTTPbody, JSONbodyParser, queryParser, lookupMimeType } +module.exports = { + findFirstBrac, + HTTPbody, + JSONbodyParser, + queryParser, + lookupMimeType, +};