Home > Software engineering >  C# System.IndexOutOfRangeException: Index was outside the bounds of the array. But when I check it m
C# System.IndexOutOfRangeException: Index was outside the bounds of the array. But when I check it m

Time:11-03

My problem is probably stupid, but I can't figure out the solution by myself, so I hope someone here can help me. I am trying to make a dll file for hosting a server on the localhost. I thought I did everything right, but I receive this error:

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at minihttpc.Requests.HttpRequest.ParseHeaders(String[] requestLine) in C:\Users\deqnb\OneDrive\minihttpc\minihttpc\Requests\HttpRequest.cs:line 87
   at minihttpc.Requests.HttpRequest.ParseRequest(String requestString) in C:\Users\deqnb\OneDrive\minihttpc\minihttpc\Requests\HttpRequest.cs:line 44
   at minihttpc.Requests.HttpRequest..ctor(String requestString) in C:\Users\deqnb\OneDrive\minihttpc\minihttpc\Requests\HttpRequest.cs:line 21
   at MiniServerHTTP.WebServer.ConnectionHandler.ReadRequest() in C:\Users\deqnb\OneDrive\minihttpc\MiniServerHTTP.WebServer\ConnectionHandler.cs:line 80
   at MiniServerHTTP.WebServer.ConnectionHandler.ProcessRequest() in C:\Users\deqnb\OneDrive\minihttpc\MiniServerHTTP.WebServer\ConnectionHandler.cs:line 28

Here is my code: HttpRequest.cs:

using minihttpc.Common.CoreValidator;
using minihttpc.Common.GlobalConstants;
using minihttpc.Headers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace minihttpc.Requests
{
    public class HttpRequest:IHttpRequest
    {
        public HttpRequest(string requestString)
        {
            CoreValidator.ThrowIfNullOrEmpty(requestString, nameof(requestString));

            this.FormData = new Dictionary<string, object>();
            this.QueryData = new Dictionary<string, object>();
            this.Headers = new HttpHeaderCollection();

            this.ParseRequest(requestString);
        }
        public string Path { get; private set; }
        public string Url { get; private set; }
        public Dictionary<string,object>FormData { get; }
        public Dictionary<string, object> QueryData { get; }
        public IHttpHeaderCollection Headers { get; private set; }
        public HttpRequestMethod RequestMethod { get; private set; }

       
        public void ParseRequest(string requestString)
        {
            string[] splitRequestContent = requestString.Split(new[] { 
GlobalConstants.HttpNewLine }, StringSplitOptions.None);
            string[] requestLine = splitRequestContent[0].Trim().Split(new[] 
{ ' ' }, StringSplitOptions.RemoveEmptyEntries);

            if (!this.IsValidReqiestLine(requestLine))
            {
                throw new BadRequestException();
            }

            this.ParseRequestMethod(requestLine);
            this.ParseRequestUrl(requestLine);
            this.ParseRequestPath();
            this.ParseHeaders(splitRequestContent.Skip(1).ToArray());
            //this.ParseRequestQuerryParameters();
            this.ParseRequestParameters(splitRequestContent[splitRequestContent.Length - 1]);

        }
        bool IsValidReqiestLine(string[] requestLine)
        {
            if(requestLine.Count()!=3&&requestLine[2] != "HTTP/1.1")
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        void ParseRequestMethod(string[] requestLine)
        {
            switch (requestLine[0])
            {
                case "GET": RequestMethod = HttpRequestMethod.Get; break;
                case "POST": RequestMethod = HttpRequestMethod.Post; break;
                case "PUT": RequestMethod = HttpRequestMethod.Put; break;
                case "DELETE": RequestMethod = HttpRequestMethod.Delete; break;
            }
        }
        void ParseRequestUrl(string [] requestLine)
        {
            this.Url = requestLine[1];
        }
        void ParseRequestPath()
        {
            this.Path = this.Url.Split("?").Take(1).First().ToString();
        }
        void ParseHeaders(string [] requestLine)
        {
            foreach(var line in requestLine)
            {
                Console.WriteLine(line); //a lot of info about the req
                if (line == GlobalConstants.HttpNewLine) break;

                string[] header = line.Split(' ').ToArray();
                //Console.WriteLine(header[1]);
                Headers.AddHeader(new HttpHeader(header[0],
 header[1]));//seems fine //line 87
            }
            if (Headers.ContainsHeader("host"))
            {
                throw new BadRequestException();
            }
        }
        void ParseRequestQuerryParameters()
        {
            if (!(this.Url.Split('?').Length > 1)) return;
            this.Url.Split('?', '#')[1].Split('&').Select(plainQuerryParameter => 
plainQuerryParameter.Split());//not finished !!!!
        }
        void ParseFormDataParameters(string formData)
        {
            if (!string.IsNullOrEmpty(formData))
            {
                formData.Split('&').Select(plainQueryParameter => 
plainQueryParameter.Split('=')).ToList().ForEach(queryParameterKeyValue =>
                this.FormData.Add(queryParameterKeyValue[0], 
queryParameterKeyValue[1]));
            }
        }
        void ParseRequestParameters(string formData)//not being called
        {
            ParseRequestQuerryParameters();
            ParseFormDataParameters(formData);
        }
    }
}
ConnectionHandler.cs:
using minihttpc.Common.CoreValidator;
using minihttpc.Requests;
using MiniServerHTTP.WebServer.Results;
using MiniServerHTTP.WebServer.Routing;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace MiniServerHTTP.WebServer
{
    public class ConnectionHandler
    {
        private readonly Socket client;
        private readonly IServerRoutingTable table;
        public ConnectionHandler(Socket client, IServerRoutingTable table)
        {
            CoreValidator.ThrowIfNull(client, nameof(client));
            CoreValidator.ThrowIfNull(client, nameof(client));
            this.client = client;
            this.table = table;
        }
        public async Task ProcessRequest()
        {
            try
            {
                var httpRequest = await this.ReadRequest();
                if (httpRequest != null)
                {
                    Console.WriteLine($"Processing: {httpRequest.RequestMethod} {httpRequest.Path}...");
                    var httpResponse = this.HandleRequest((IHttpRequest)httpRequest);
                    this.ProcessResponse(httpResponse);
                }
            }
            catch (BadRequestException e)//400
            {
                this.ProcessResponse(new TextResult(e.ToString(), 
HttpResponseStatusCode.BadRequest));
            }
            catch (Exception e)//500
            {
                this.ProcessResponse(new TextResult(e.ToString(), 
HttpResponseStatusCode.InternalServerError));
            }
            this.client.Shutdown(SocketShutdown.Both);
        }

        private async Task ProcessResponse(IHttpResponse httpResponse)
        {
            byte[] byteSegments = httpResponse.GetBytes();
            await this.client.SendAsync(byteSegments, SocketFlags.None);
        }

        private IHttpResponse HandleRequest(IHttpRequest httpRequest)
        {
            if(!this.table.Contains(httpRequest.RequestMethod, 
httpRequest.Path))
            {
                return new TextResult($"Route with method {httpRequest.RequestMethod} and path \"{httpRequest.Path}\"not found.", 
HttpResponseStatusCode.NotFound);
            }
            return this.table.Get(httpRequest.RequestMethod, 
httpRequest.Path).Invoke(httpRequest);
        }

        private async Task<HttpRequest> ReadRequest()
        {
            var result = new StringBuilder();
            var data = new ArraySegment<byte>(new byte[1024]);
            while (true)
            {
                int numberOfBytes = await this.client.ReceiveAsync(data.Array, SocketFlags.None);
                if (numberOfBytes == 0) break;
                var bytesAsString = Encoding.UTF8.GetString(data.Array, 0,
 numberOfBytes);
                result.Append(bytesAsString);
                if (numberOfBytes < 1023) break;
               
            }
            if (result.Length == 0)
            {
                return null;
            }

            return new HttpRequest(result.ToString());
        }
    }
}

When I check manualy the parameters and variables in minihttpc.Requests.HttpRequest.ParseHeaders() everything seems good. I can't get where is the problem.

CodePudding user response:

string[] header = line.Split(' ').ToArray();
Headers.AddHeader(new HttpHeader(header[0], header[1]));

I can pretty much guarantee you're running into a line that doesn't have a space in it. Maybe there's a line that's empty, for example. That wouldn't be obvious from the Console.WriteLine() that you're doing, because empty lines are kind of invisible.

  • Related