Http_read_data/3 parsing error

I’m using: SWI-Prolog version 9.1.1

I want the code to: solve http_read_data/3 error (also http_parmeter)

But what I’m getting is: Illegal HTTP parameter error

Hello, I’m currently writing a code to receive an email and send it to the email I received, but I think I keep getting errors in the process of parsing the input value. I was wondering if there was a problem with the email process, so I tested it with a command like send_reset_password_handler ([email='kimdk9829@gmail.com ']) on the debug console, but it seems that there is no problem with the email transfer handler as it seems to be sent normally. Therefore, I think there is a problem with simply receiving and interpreting the input value, but I don’t know why. I’ve tried it with http_parameter instead of http_read_data, but the error still comes up. I’m asking if you can give me any hints or help with the problem. Thank you.

My code looks like this:

:- module(send_email, [forgot_password_form_handler/1, send_reset_password_handler/1]). 

:- use_module(library(http/http_dispatch)).
:- use_module(library(http/html_write)).
:- use_module(library(http/http_parameters)).
:- use_module(library(smtp)).
:- use_module(library(http/http_client)).
:- use_module(library(http/http_header)).

:- http_handler(root(forgot_password_form), forgot_password_form_handler, [method(get)]).
:- http_handler(root(forgot_password), send_reset_password_handler, [method(post)]).

forgot_password_form_handler(_Request) :-
    reply_html_page(
        title('Forgot Password'),
        div(class('forgot-password-form-container'), [
            style('.forgot-password-form-container { max-width: 300px; margin: auto; } .forgot-password-form-container label { display: inline-block; width: 80px; } .forgot-password-form-container input[type="text"] { width: calc(100% - 90px); }'),
            form([ id('forgot-password-form'), action('/forgot_password'), method('POST') ], [
                div(class('form-group'), [
                    label([for=email], 'Email: '),
                    input([type=text, name=email, id=email, class('form-control')])
                ]),
                div(class('form-group'), [
                    input([type=submit, value='Reset Password', class('btn btn-primary')])
                ])
            ])
        ])
    ).

send_reset_password_handler(Request) :-
    (   member(method(post), Request)
    ->  http_read_data(Request, Data, [])
    ;   Data = Request  
    ),
    format('Received data: ~w~n', [Data]),
    (   member(email=Email, Data) 
    ->  format('Email found: ~w~n', [Email]),
        (   send_email:send_reset_email(Email)
        ->  writeln('Email sent successfully'),
            reply_html_page(
                title('Email Sent'),
                p('A reset password email has been sent to your address.')
            )
        ;   writeln('Failed to send email'),
            reply_html_page(
                title('Email Failed'),
                p('Failed to send the reset password email. Please try again.')
            )
        )
    ;   writeln('Email not found in data'),
        reply_html_page(
            title('Error'),
            p('No email address provided.')
        )
    ).

send_reset_email(Email) :-
    smtp_options(Options),
    catch(
        smtp_send_mail(
            Email,
            send_reset_message,
            [ subject('Reset Your Password'),
              from('kimdk9829@gmail.com')
            | Options ]
        ),
        _Error,  
        false   
    ).```

You cannot write to current_output from an HTTP handler. That will end up in the reply, breaking the reply. You can write to user_error. Better, use debug/3.

For a form, http_parameters/2 should do the job.

For debugging, you may wish to load library(http/http_error), which will add a stack trace to the error report. You can also do

?- tspy(send_reset_password_handler/1).

And send the form. That should open the debugger, so you can see what is going on.

1 Like

As you said, I changed the error debugging form, but I’m not sure how to debug it :frowning:

send_reset_password_handler(Request) :-
    debug(http, 'Handling request: ~w', [Request]),
    
    (   member(method(post), Request)
    ->  debug(http, 'POST request received', []),
        
        catch(http_parameters(Request, [email(Email, [string])]),
              Error,
              (debug(http, 'Error reading parameters: ~w', [Error]), fail)),
        
        debug(http, 'Email found: ~w', [Email]),

        (   send_email:send_reset_email(Email)
        ->  debug(http, 'Email sent successfully', []),
            reply_html_page(
                title('Email Sent'),
                p('A reset password email has been sent to your address.')
            )
        ;   debug(http, 'Failed to send email', []),
            reply_html_page(
                title('Email Failed'),
                p('Failed to send the reset password email. Please try again.')
            )
        )
    ;   debug(http, 'Not a POST request', []),
        reply_html_page(
            title('Error'),
            p('Request was not a POST request.')
        )
    ).

this is a code, and i started shell like this;

root@dac5574b15d5:/swish/lib/plugin# swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 9.1.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- [send_email].
true.

?- use_module(library(http/http_error)).
true.

?- tspy(send_reset_password_handler/1).
% Spy point on send_email:send_reset_password_handler/1
true.

I’m not sure how to debug after this. I opened another terminal window and tested it with a curl request, and the debug message Failed to send the reset password email. Please try again. There’s no response to the debugging window…

To activate the debug channel, you use

?- debug(http).

tspy/1 should work. Your version is pretty old though. The alternative is to simply add a call to gtrace at the place where you would like to start the debugger. Note that GUI access must work. You can try typing

?- emacs.

to see whether the built-in emacs clone comes up.

1 Like