module gemini implicit none contains subroutine read_request(ssl, req) use jessl, only: ssl_read use iso_c_binding implicit none type(c_ptr)::ssl character(*), intent(out)::req character, dimension(64)::buf integer::bufread integer::i, j req = " " i = 1 bufread = ssl_read(ssl, buf) do while(bufread > 0) do j = 1, bufread if(buf(j) == c_new_line) then exit end if if(buf(j) /= c_carriage_return) then req(i:i) = buf(j) i = i + 1 end if end do if(buf(j) == c_new_line) then exit end if bufread = ssl_read(ssl, buf) end do end subroutine read_request function read_into_buffer(unit_number, buffer) implicit none integer, intent(in)::unit_number character, dimension(*), intent(out)::buffer integer::read_into_buffer integer::i, ierr ierr = 0 i = 0 do while(ierr == 0 .and. i < len(buffer)) i = i + 1 read(unit_number, iostat=ierr) buffer(i) end do if(ierr /= 0) then i = i - 1 end if read_into_buffer = i end function read_into_buffer subroutine write_file(ssl, unit_number, mimetype) use iso_c_binding, only: c_ptr, c_carriage_return, c_new_line use jessl, only: ssl_write implicit none type(c_ptr)::ssl integer, intent(in)::unit_number character(*), intent(in)::mimetype character, dimension(64)::buf integer::buflen, written call write_string(ssl, "20 "//trim(mimetype)//c_carriage_return//c_new_line) buflen = read_into_buffer(unit_number, buf) do while(buflen > 0) written = ssl_write(ssl, buf(1:buflen)) buflen = read_into_buffer(unit_number, buf) end do end subroutine write_file subroutine handle_request() use jessl use iso_c_binding use config use iso_fortran_env use external_handling, only: external_request_gemini implicit none ! For our TLS connection type(c_ptr)::ctx type(c_ptr)::method type(c_ptr)::ssl integer(kind=c_long)::res ! Requested file character(1024)::request character(512)::mimetype integer::rendered_unit call library_init() method = tls_server_method() ctx = ctx_new(method) if(.not. C_ASSOCIATED(ctx)) then call write_log("Context failed") return end if ! Seems to be a dummy now... !res = ctx_set_ecdh_auto(ctx, 1) if(.not. ctx_use_certificate_file(ctx, trim(pubcert), SSL_FILETYPE_PEM)) then call write_log("Cert file failed") call write_log("Public: "//trim(pubcert)) !call print_error() return end if if(.not. ctx_use_private_key_file(ctx, trim(privcert), SSL_FILETYPE_PEM)) then call write_log("Cert file failed") call write_log("Private: "//trim(privcert)) !call print_error() return end if ssl = ssl_new(ctx) call write_log("Initiating connection") ! So this is a GNU Extension... res = set_read_fd(ssl, fnum(input_unit)) if(res /= 1) then call write_log("set rfd failed") !call print_error() return end if res = set_write_fd(ssl, fnum(output_unit)) if(res /= 1) then call write_log("set wfd failed") !call print_error() return end if res = ssl_accept(ssl) if(res <= 0) then call write_log("ssl_accept failed") !call print_error() return end if call write_log("Handling read_request") ! Do the actual protocol nonsense call read_request(ssl, request) call write_log("Request is "//trim(request)) if(len_trim(request) .ge. 4) then if(request(1:4) == '/api') then !call handle_api_request(request) else rendered_unit = external_request_gemini(request) end if else rendered_unit = external_request_gemini(request) end if call write_file(ssl, rendered_unit, "text/gemini") close(rendered_unit) end subroutine handle_request end module gemini