.nethttp-post

C# RestSharp POST request to Texas Parks & Wildlife TORA system returns initial page instead of search results


I'm trying to automate a search on the Texas Parks & Wildlife Department's TORA (Boat/Motor Ownership Inquiry) system using C# and RestSharp. While I can successfully navigate through the initial steps (getting session tokens and accepting terms), my final POST request to search for a company just returns the same requester page instead of any search results. I am able to do the first https://apps.tpwd.state.tx.us/tora/legal.jsf Here is the final webpage that I have issues with https://apps.tpwd.state.tx.us/tora/requester.jsf

Here's what I've implemented so far:

  1. Initial GET request to get JSESSIONID and CSRF token
  2. POST request to accept legal terms
  3. GET request to requester.faces to get new tokens
  4. Final POST request to perform the search
// Step 1: Initial GET request to retrieve the page and cookies

            Console.WriteLine("Hello, World!");

            var options = new RestClientOptions("https://apps.tpwd.state.tx.us")
            {
                MaxTimeout = -1,
            };
            var client = new RestClient(options);

            // Step 1: Get JSESSIONID
            var initRequest = new RestRequest("/tora/legal.jsf", Method.Get);
            var initResponse = await client.ExecuteAsync(initRequest);

            var jsessionId = initResponse.Cookies
                .FirstOrDefault(c => c.Name == "JSESSIONID")?.Value;

            

            if (string.IsNullOrEmpty(jsessionId))
            {
                Console.WriteLine("Failed to retrieve JSESSIONID");
                return;
            }
            else
            {
                Console.WriteLine("jsessionId: " + jsessionId);
               
            }


            // Load the HTML content into HtmlAgilityPack
            var htmlDoc = new HtmlDocument();
            htmlDoc.LoadHtml(initResponse.Content);
            Console.WriteLine(initResponse.Content);
            // Extract the _csrf token and javax.faces.ViewState
            var csrfTokenNode = htmlDoc.DocumentNode.SelectSingleNode("//input[@name='_csrf']");
            var viewStateNode = htmlDoc.DocumentNode.SelectSingleNode("//input[@name='javax.faces.ViewState']");
            string csrfToken = string.Empty;
            string viewState = string.Empty;
            if (csrfTokenNode != null && viewStateNode != null)
            {
                 csrfToken = csrfTokenNode.GetAttributeValue("value", string.Empty);
                 viewState = viewStateNode.GetAttributeValue("value", string.Empty);

                Console.WriteLine("CSRF Token: " + csrfToken);
                Console.WriteLine("ViewState: " + viewState);
            }
            else
            {
                Console.WriteLine("CSRF token or ViewState not found!");
            }

            // Step 2: Accept Terms (POST to /tora/legal.jsf)
            var acceptRequest = new RestRequest("/tora/legal.jsf", Method.Post);
            acceptRequest.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            acceptRequest.AddHeader("Cookie", $"JSESSIONID={jsessionId}");
            acceptRequest.AddParameter("form", "form");
            acceptRequest.AddParameter("form:accept", "Accept");
            acceptRequest.AddParameter("form:_idcl", "");
            acceptRequest.AddParameter("_csrf", csrfToken);
            acceptRequest.AddParameter("javax.faces.ViewState", viewState);

            var acceptResponse = await client.ExecuteAsync(acceptRequest);
            if (!acceptResponse.IsSuccessful)
            {
                Console.WriteLine("Failed to accept terms.");
                return;
            }
            else
            {
                Console.WriteLine("acceptResponse: " + acceptResponse.Content);
            }

            var ssm_au_c = acceptResponse.Cookies
                .FirstOrDefault(c => c.Name == "ssm_au_c")?.Value;

            var pkCookieID = acceptResponse.Cookies
                .FirstOrDefault(c => c.Name == "_pk_id.9.df1b")?.Value;

            var pkCookieSes = acceptResponse.Cookies
                .FirstOrDefault(c => c.Name == "_pk_ses.9.df1b")?.Value;

            Console.WriteLine("ssm_au_c " + ssm_au_c);
            Console.WriteLine("pkCookieID " + pkCookieID);
            Console.WriteLine("pkCookieSes " + pkCookieSes);

            // Step 3: GET the requester.faces page to get new tokens
            var getRequesterPage = new RestRequest("/tora/requester.faces", Method.Get);
            getRequesterPage.AddHeader("Cookie", $"JSESSIONID={jsessionId}");
            var requesterResponse = await client.ExecuteAsync(getRequesterPage);

            // Get new tokens from the requester page
            var requesterDoc = new HtmlDocument();
            requesterDoc.LoadHtml(requesterResponse.Content);
            var newCsrfToken = requesterDoc.DocumentNode.SelectSingleNode("//input[@name='_csrf']")?.GetAttributeValue("value", string.Empty);
            var newViewState = requesterDoc.DocumentNode.SelectSingleNode("//input[@name='javax.faces.ViewState']")?.GetAttributeValue("value", string.Empty);

            if (string.IsNullOrEmpty(newCsrfToken) || string.IsNullOrEmpty(newViewState))
            {
                Console.WriteLine("Failed to get new tokens from requester page");
                return;
            }

            // Now update your final POST request to use the new tokens
            var request = new RestRequest("/tora/requester.faces", Method.Post);
            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            request.AddHeader("Cookie", $"JSESSIONID={jsessionId}");
            request.AddHeader("Referer", "https://apps.tpwd.state.tx.us/tora/requester.faces");

            // Basic form parameters
            request.AddParameter("form", "form");
            request.AddParameter("form:hasCompany", "true");
            request.AddParameter("form:company", "Texans Credit Union");
            request.AddParameter("form:address1", "777 E Campbell Rd");
            request.AddParameter("form:city", "Richardson");
            request.AddParameter("form:state", "TX");
            request.AddParameter("form:zip", "75081");
            request.AddParameter("form:search", "Search");
            request.AddParameter("_csrf", newCsrfToken);
            request.AddParameter("javax.faces.ViewState", newViewState);
            // Add these JSF-specific parameters
            request.AddParameter("javax.faces.partial.ajax", "true");
            request.AddParameter("javax.faces.source", "form:search");
            request.AddParameter("javax.faces.partial.execute", "@all");
            request.AddParameter("javax.faces.partial.render", "@all");

            ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;

            var response = await client.ExecuteAsync(request);
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine("Final Response:");
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine(response.Content);

            if (response.Content.Contains("Vessel/Boat "))
            {
                Console.WriteLine("The string contains 'Vessel/Boat '.");
            }
            else
            {
                Console.WriteLine("The string does not contain 'Vessel/Boat '.");
            }

            if (response.StatusCode != HttpStatusCode.OK)
            {
                Console.WriteLine($"Request failed with status code: {response.StatusCode}");
                Console.WriteLine($"Response content: {response.Content}");
            }

            Console.WriteLine("end program");

When I submit this request, instead of getting search results, I just get back the same requester.faces page HTML. The actual website (https://apps.tpwd.state.tx.us/tora/requester.jsf) works fine when used manually through a browser.

What I've tried:

What am I missing in my POST request to get actual search results instead of just getting the same page back?

Environment:

I also was able to do the post call through postman.

Im not sure what i am doing wrong....

Any help would be greatly appreciated!


Solution

  • I changed up some of the headers using postman/fiddler/etc. Also, I did the same http post twice in a row and it passes to the next page. Not sure why.

    So it's working now...

    Here is the updated code:

    var request4 = new RestRequest("/tora/requester.jsf", Method.Post);
    
    request4.AddHeader("Host", "apps.tpwd.state.tx.us");
    request4.AddHeader("Connection", "keep-alive");
    
    request4.AddHeader("Cache-Control", "max-age=0");
    request4.AddHeader("sec-ch-ua", "\"Chromium\";v=\"134\", \"Not:A-Brand\";v=\"24\", \"Google Chrome\";v=\"134\"");
    request4.AddHeader("sec-ch-ua-mobile", "?0");
    request4.AddHeader("sec-ch-ua-platform", "\"Windows\"");
    request4.AddHeader("Origin", "https://apps.tpwd.state.tx.us");
    request4.AddHeader("Content-Type", "application/x-www-form-urlencoded");
    request4.AddHeader("Upgrade-Insecure-Requests", "1");
    request4.AddHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36");
    request4.AddHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
    request4.AddHeader("Sec-Fetch-Site", "same-origin");
    request4.AddHeader("Sec-Fetch-Mode", "navigate");
    request4.AddHeader("Sec-Fetch-User", "?1");
    request4.AddHeader("Sec-Fetch-Dest", "document");
    request4.AddHeader("Referer", "https://apps.tpwd.state.tx.us/tora/requester.jsf");
    request4.AddHeader("Accept-Encoding", "gzip, deflate, br, zstd");
    request4.AddHeader("Accept-Language", "en-US,en;q=0.9");
    
    AddCookies(request4);
    
    request4.AddParameter("form", "form");
    request4.AddParameter("_csrf", csrfToken);
    request4.AddParameter("hasCompany", "true");
    request4.AddParameter("foreign", "false");
    request4.AddParameter("company", "TEXANS CREDIT UNION");
    request4.AddParameter("address1", "777 E CAMPBELL RD");
    request4.AddParameter("address2", "");
    request4.AddParameter("city", "RICHARDSON");
    request4.AddParameter("state", "TX");
    request4.AddParameter("zip", "75081");
    request4.AddParameter("javax.faces.ViewState", viewState);
    request4.AddParameter("search", "search");
    
    
    var response4 = await _client.ExecuteAsync(request4);
    
    if (response4.IsSuccessful)
    {
        Console.WriteLine("POST requester.jsf successful");
        Console.WriteLine(response4.Content); // Display the content for inspection
        ParseCookies(response4);
    }
    else
    {
        Console.WriteLine($"POST requester.jsf failed: {response4.ErrorMessage}");
    }
    
    var response4Again = await _client.ExecuteAsync(request4);
    
    if (response4Again.IsSuccessful)
    {
        Console.WriteLine("POST requester.jsf successful");
        Console.WriteLine(response4.Content); // Display the content for inspection
        ParseCookies(response4);
    }
    else
    {
        Console.WriteLine($"POST requester.jsf failed: {response4.ErrorMessage}");
    }