mirror of
				https://github.com/lightpanda-io/browser.git
				synced 2025-10-30 15:41:48 +00:00 
			
		
		
		
	Initial work on integrating libcurl and making all http nonblocking
This commit is contained in:
		
							
								
								
									
										93
									
								
								src/http/ca_certs.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/http/ca_certs.zig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| // Copyright (C) 2023-2025  Lightpanda (Selecy SAS) | ||||
| // | ||||
| // Francis Bouvier <francis@lightpanda.io> | ||||
| // Pierre Tachoire <pierre@lightpanda.io> | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU Affero General Public License as | ||||
| // published by the Free Software Foundation, either version 3 of the | ||||
| // License, or (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU Affero General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU Affero General Public License | ||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| const std = @import("std"); | ||||
| const c = @import("client.zig").c; | ||||
|  | ||||
| const Allocator = std.mem.Allocator; | ||||
|  | ||||
| // TODO: on BSD / Linux, we could just read the PEM file directly. | ||||
| // This whole rescan + decode is really just needed for MacOS. On Linux | ||||
| // bundle.rescan does find the .pem file(s) which could be in a few different | ||||
| // places, so it's still useful, just not efficient. | ||||
| pub fn load(allocator: Allocator, arena: Allocator) !c.curl_blob { | ||||
|     var bundle: std.crypto.Certificate.Bundle = .{}; | ||||
|     try bundle.rescan(allocator); | ||||
|     defer bundle.deinit(allocator); | ||||
|  | ||||
|     var it = bundle.map.valueIterator(); | ||||
|     const bytes = bundle.bytes.items; | ||||
|  | ||||
|     const encoder = std.base64.standard.Encoder; | ||||
|     var arr: std.ArrayListUnmanaged(u8) = .empty; | ||||
|  | ||||
|     const encoded_size = encoder.calcSize(bytes.len); | ||||
|     const buffer_size = encoded_size + | ||||
|         (bundle.map.count() * 75) +  // start / end per certificate + extra, just in case | ||||
|         (encoded_size / 64)          // newline per 64 characters | ||||
|     ; | ||||
|     try arr.ensureTotalCapacity(arena, buffer_size); | ||||
|     var writer = arr.writer(arena); | ||||
|  | ||||
|     while (it.next()) |index| { | ||||
|         const cert = try std.crypto.Certificate.der.Element.parse(bytes, index.*); | ||||
|  | ||||
|         try writer.writeAll("-----BEGIN CERTIFICATE-----\n"); | ||||
|         var line_writer = LineWriter{.inner = writer}; | ||||
|         try encoder.encodeWriter(&line_writer, bytes[index.*..cert.slice.end]); | ||||
|         try writer.writeAll("\n-----END CERTIFICATE-----\n"); | ||||
|     } | ||||
|  | ||||
|     // Final encoding should not be larger than our initial size estimate | ||||
|     std.debug.assert(buffer_size > arr.items.len); | ||||
|  | ||||
|     return .{ | ||||
|         .len = arr.items.len, | ||||
|         .data = arr.items.ptr, | ||||
|         .flags = 0, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| // Wraps lines @ 64 columns | ||||
| const LineWriter = struct { | ||||
|     col: usize = 0, | ||||
|     inner: std.ArrayListUnmanaged(u8).Writer, | ||||
|  | ||||
|     pub fn writeAll(self: *LineWriter, data: []const u8) !void { | ||||
|         var writer = self.inner; | ||||
|  | ||||
|         var col = self.col; | ||||
|         const len = 64 - col; | ||||
|  | ||||
|         var remain = data; | ||||
|         if (remain.len > len) { | ||||
|             col = 0; | ||||
|             try writer.writeAll(data[0..len]); | ||||
|             try writer.writeByte('\n'); | ||||
|             remain = data[len..]; | ||||
|         } | ||||
|  | ||||
|         while (remain.len > 64) { | ||||
|             try writer.writeAll(remain[0..64]); | ||||
|             try writer.writeByte('\n'); | ||||
|             remain = data[len..]; | ||||
|         } | ||||
|         try writer.writeAll(remain); | ||||
|         self.col = col + remain.len; | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										4351
									
								
								src/http/client.zig
									
									
									
									
									
								
							
							
						
						
									
										4351
									
								
								src/http/client.zig
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										238
									
								
								src/http/errors.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								src/http/errors.zig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,238 @@ | ||||
| // Copyright (C) 2023-2025  Lightpanda (Selecy SAS) | ||||
| // | ||||
| // Francis Bouvier <francis@lightpanda.io> | ||||
| // Pierre Tachoire <pierre@lightpanda.io> | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU Affero General Public License as | ||||
| // published by the Free Software Foundation, either version 3 of the | ||||
| // License, or (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU Affero General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU Affero General Public License | ||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| const std = @import("std"); | ||||
| const c = @import("client.zig").c; | ||||
|  | ||||
| pub const Error = error { | ||||
|     UnsupportedProtocol, | ||||
|     FailedInit, | ||||
|     UrlMalformat, | ||||
|     NotBuiltIn, | ||||
|     CouldntResolveProxy, | ||||
|     CouldntResolveHost, | ||||
|     CouldntConnect, | ||||
|     WeirdServerReply, | ||||
|     RemoteAccessDenied, | ||||
|     FtpAcceptFailed, | ||||
|     FtpWeirdPassReply, | ||||
|     FtpAcceptTimeout, | ||||
|     FtpWeirdPasvReply, | ||||
|     FtpWeird227Format, | ||||
|     FtpCantGetHost, | ||||
|     Http2, | ||||
|     FtpCouldntSetType, | ||||
|     PartialFile, | ||||
|     FtpCouldntRetrFile, | ||||
|     QuoteError, | ||||
|     HttpReturnedError, | ||||
|     WriteError, | ||||
|     UploadFailed, | ||||
|     ReadError, | ||||
|     OutOfMemory, | ||||
|     OperationTimedout, | ||||
|     FtpPortFailed, | ||||
|     FtpCouldntUseRest, | ||||
|     RangeError, | ||||
|     SslConnectError, | ||||
|     BadDownloadResume, | ||||
|     FileCouldntReadFile, | ||||
|     LdapCannotBind, | ||||
|     LdapSearchFailed, | ||||
|     AbortedByCallback, | ||||
|     BadFunctionArgument, | ||||
|     InterfaceFailed, | ||||
|     TooManyRedirects, | ||||
|     UnknownOption, | ||||
|     SetoptOptionSyntax, | ||||
|     GotNothing, | ||||
|     SslEngineNotfound, | ||||
|     SslEngineSetfailed, | ||||
|     SendError, | ||||
|     RecvError, | ||||
|     SslCertproblem, | ||||
|     SslCipher, | ||||
|     PeerFailedVerification, | ||||
|     BadContentEncoding, | ||||
|     FilesizeExceeded, | ||||
|     UseSslFailed, | ||||
|     SendFailRewind, | ||||
|     SslEngineInitfailed, | ||||
|     LoginDenied, | ||||
|     TftpNotfound, | ||||
|     TftpPerm, | ||||
|     RemoteDiskFull, | ||||
|     TftpIllegal, | ||||
|     TftpUnknownid, | ||||
|     RemoteFileExists, | ||||
|     TftpNosuchuser, | ||||
|     SslCacertBadfile, | ||||
|     RemoteFileNotFound, | ||||
|     Ssh, | ||||
|     SslShutdownFailed, | ||||
|     Again, | ||||
|     SslCrlBadfile, | ||||
|     SslIssuerError, | ||||
|     FtpPretFailed, | ||||
|     RtspCseqError, | ||||
|     RtspSessionError, | ||||
|     FtpBadFileList, | ||||
|     ChunkFailed, | ||||
|     NoConnectionAvailable, | ||||
|     SslPinnedpubkeynotmatch, | ||||
|     SslInvalidcertstatus, | ||||
|     Http2Stream, | ||||
|     RecursiveApiCall, | ||||
|     AuthError, | ||||
|     Http3, | ||||
|     QuicConnectError, | ||||
|     Proxy, | ||||
|     SslClientcert, | ||||
|     UnrecoverablePoll, | ||||
|     TooLarge, | ||||
|     Unknown, | ||||
| }; | ||||
|  | ||||
| pub fn fromCode(code: c.CURLcode) Error { | ||||
|     std.debug.assert(code != c.CURLE_OK); | ||||
|  | ||||
|     return switch (code) { | ||||
|         c.CURLE_UNSUPPORTED_PROTOCOL => Error.UnsupportedProtocol, | ||||
|         c.CURLE_FAILED_INIT => Error.FailedInit, | ||||
|         c.CURLE_URL_MALFORMAT => Error.UrlMalformat, | ||||
|         c.CURLE_NOT_BUILT_IN => Error.NotBuiltIn, | ||||
|         c.CURLE_COULDNT_RESOLVE_PROXY => Error.CouldntResolveProxy, | ||||
|         c.CURLE_COULDNT_RESOLVE_HOST => Error.CouldntResolveHost, | ||||
|         c.CURLE_COULDNT_CONNECT => Error.CouldntConnect, | ||||
|         c.CURLE_WEIRD_SERVER_REPLY => Error.WeirdServerReply, | ||||
|         c.CURLE_REMOTE_ACCESS_DENIED => Error.RemoteAccessDenied, | ||||
|         c.CURLE_FTP_ACCEPT_FAILED => Error.FtpAcceptFailed, | ||||
|         c.CURLE_FTP_WEIRD_PASS_REPLY => Error.FtpWeirdPassReply, | ||||
|         c.CURLE_FTP_ACCEPT_TIMEOUT => Error.FtpAcceptTimeout, | ||||
|         c.CURLE_FTP_WEIRD_PASV_REPLY => Error.FtpWeirdPasvReply, | ||||
|         c.CURLE_FTP_WEIRD_227_FORMAT => Error.FtpWeird227Format, | ||||
|         c.CURLE_FTP_CANT_GET_HOST => Error.FtpCantGetHost, | ||||
|         c.CURLE_HTTP2 => Error.Http2, | ||||
|         c.CURLE_FTP_COULDNT_SET_TYPE => Error.FtpCouldntSetType, | ||||
|         c.CURLE_PARTIAL_FILE => Error.PartialFile, | ||||
|         c.CURLE_FTP_COULDNT_RETR_FILE => Error.FtpCouldntRetrFile, | ||||
|         c.CURLE_QUOTE_ERROR => Error.QuoteError, | ||||
|         c.CURLE_HTTP_RETURNED_ERROR => Error.HttpReturnedError, | ||||
|         c.CURLE_WRITE_ERROR => Error.WriteError, | ||||
|         c.CURLE_UPLOAD_FAILED => Error.UploadFailed, | ||||
|         c.CURLE_READ_ERROR => Error.ReadError, | ||||
|         c.CURLE_OUT_OF_MEMORY => Error.OutOfMemory, | ||||
|         c.CURLE_OPERATION_TIMEDOUT => Error.OperationTimedout, | ||||
|         c.CURLE_FTP_PORT_FAILED => Error.FtpPortFailed, | ||||
|         c.CURLE_FTP_COULDNT_USE_REST => Error.FtpCouldntUseRest, | ||||
|         c.CURLE_RANGE_ERROR => Error.RangeError, | ||||
|         c.CURLE_SSL_CONNECT_ERROR => Error.SslConnectError, | ||||
|         c.CURLE_BAD_DOWNLOAD_RESUME => Error.BadDownloadResume, | ||||
|         c.CURLE_FILE_COULDNT_READ_FILE => Error.FileCouldntReadFile, | ||||
|         c.CURLE_LDAP_CANNOT_BIND => Error.LdapCannotBind, | ||||
|         c.CURLE_LDAP_SEARCH_FAILED => Error.LdapSearchFailed, | ||||
|         c.CURLE_ABORTED_BY_CALLBACK => Error.AbortedByCallback, | ||||
|         c.CURLE_BAD_FUNCTION_ARGUMENT => Error.BadFunctionArgument, | ||||
|         c.CURLE_INTERFACE_FAILED => Error.InterfaceFailed, | ||||
|         c.CURLE_TOO_MANY_REDIRECTS => Error.TooManyRedirects, | ||||
|         c.CURLE_UNKNOWN_OPTION => Error.UnknownOption, | ||||
|         c.CURLE_SETOPT_OPTION_SYNTAX => Error.SetoptOptionSyntax, | ||||
|         c.CURLE_GOT_NOTHING => Error.GotNothing, | ||||
|         c.CURLE_SSL_ENGINE_NOTFOUND => Error.SslEngineNotfound, | ||||
|         c.CURLE_SSL_ENGINE_SETFAILED => Error.SslEngineSetfailed, | ||||
|         c.CURLE_SEND_ERROR => Error.SendError, | ||||
|         c.CURLE_RECV_ERROR => Error.RecvError, | ||||
|         c.CURLE_SSL_CERTPROBLEM => Error.SslCertproblem, | ||||
|         c.CURLE_SSL_CIPHER => Error.SslCipher, | ||||
|         c.CURLE_PEER_FAILED_VERIFICATION => Error.PeerFailedVerification, | ||||
|         c.CURLE_BAD_CONTENT_ENCODING => Error.BadContentEncoding, | ||||
|         c.CURLE_FILESIZE_EXCEEDED => Error.FilesizeExceeded, | ||||
|         c.CURLE_USE_SSL_FAILED => Error.UseSslFailed, | ||||
|         c.CURLE_SEND_FAIL_REWIND => Error.SendFailRewind, | ||||
|         c.CURLE_SSL_ENGINE_INITFAILED => Error.SslEngineInitfailed, | ||||
|         c.CURLE_LOGIN_DENIED => Error.LoginDenied, | ||||
|         c.CURLE_TFTP_NOTFOUND => Error.TftpNotfound, | ||||
|         c.CURLE_TFTP_PERM => Error.TftpPerm, | ||||
|         c.CURLE_REMOTE_DISK_FULL => Error.RemoteDiskFull, | ||||
|         c.CURLE_TFTP_ILLEGAL => Error.TftpIllegal, | ||||
|         c.CURLE_TFTP_UNKNOWNID => Error.TftpUnknownid, | ||||
|         c.CURLE_REMOTE_FILE_EXISTS => Error.RemoteFileExists, | ||||
|         c.CURLE_TFTP_NOSUCHUSER => Error.TftpNosuchuser, | ||||
|         c.CURLE_SSL_CACERT_BADFILE => Error.SslCacertBadfile, | ||||
|         c.CURLE_REMOTE_FILE_NOT_FOUND => Error.RemoteFileNotFound, | ||||
|         c.CURLE_SSH => Error.Ssh, | ||||
|         c.CURLE_SSL_SHUTDOWN_FAILED => Error.SslShutdownFailed, | ||||
|         c.CURLE_AGAIN => Error.Again, | ||||
|         c.CURLE_SSL_CRL_BADFILE => Error.SslCrlBadfile, | ||||
|         c.CURLE_SSL_ISSUER_ERROR => Error.SslIssuerError, | ||||
|         c.CURLE_FTP_PRET_FAILED => Error.FtpPretFailed, | ||||
|         c.CURLE_RTSP_CSEQ_ERROR => Error.RtspCseqError, | ||||
|         c.CURLE_RTSP_SESSION_ERROR => Error.RtspSessionError, | ||||
|         c.CURLE_FTP_BAD_FILE_LIST => Error.FtpBadFileList, | ||||
|         c.CURLE_CHUNK_FAILED => Error.ChunkFailed, | ||||
|         c.CURLE_NO_CONNECTION_AVAILABLE => Error.NoConnectionAvailable, | ||||
|         c.CURLE_SSL_PINNEDPUBKEYNOTMATCH => Error.SslPinnedpubkeynotmatch, | ||||
|         c.CURLE_SSL_INVALIDCERTSTATUS => Error.SslInvalidcertstatus, | ||||
|         c.CURLE_HTTP2_STREAM => Error.Http2Stream, | ||||
|         c.CURLE_RECURSIVE_API_CALL => Error.RecursiveApiCall, | ||||
|         c.CURLE_AUTH_ERROR => Error.AuthError, | ||||
|         c.CURLE_HTTP3 => Error.Http3, | ||||
|         c.CURLE_QUIC_CONNECT_ERROR => Error.QuicConnectError, | ||||
|         c.CURLE_PROXY => Error.Proxy, | ||||
|         c.CURLE_SSL_CLIENTCERT => Error.SslClientcert, | ||||
|         c.CURLE_UNRECOVERABLE_POLL => Error.UnrecoverablePoll, | ||||
|         c.CURLE_TOO_LARGE => Error.TooLarge, | ||||
|         else => Error.Unknown, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| pub const Multi = error { | ||||
|     BadHandle, | ||||
|     BadEasyHandle, | ||||
|     OutOfMemory, | ||||
|     InternalError, | ||||
|     BadSocket, | ||||
|     UnknownOption, | ||||
|     AddedAlready, | ||||
|     RecursiveApiCall, | ||||
|     WakeupFailure, | ||||
|     BadFunctionArgument, | ||||
|     AbortedByCallback, | ||||
|     UnrecoverablePoll, | ||||
|     Unknown, | ||||
| }; | ||||
|  | ||||
| pub fn fromMCode(code: c.CURLMcode) Multi { | ||||
|     std.debug.assert(code != c.CURLM_OK); | ||||
|  | ||||
|     return switch (code) { | ||||
|         c.CURLM_BAD_HANDLE => Multi.BadHandle, | ||||
|         c.CURLM_BAD_EASY_HANDLE => Multi.BadEasyHandle, | ||||
|         c.CURLM_OUT_OF_MEMORY => Multi.OutOfMemory, | ||||
|         c.CURLM_INTERNAL_ERROR => Multi.InternalError, | ||||
|         c.CURLM_BAD_SOCKET => Multi.BadSocket, | ||||
|         c.CURLM_UNKNOWN_OPTION => Multi.UnknownOption, | ||||
|         c.CURLM_ADDED_ALREADY => Multi.AddedAlready, | ||||
|         c.CURLM_RECURSIVE_API_CALL => Multi.RecursiveApiCall, | ||||
|         c.CURLM_WAKEUP_FAILURE => Multi.WakeupFailure, | ||||
|         c.CURLM_BAD_FUNCTION_ARGUMENT => Multi.BadFunctionArgument, | ||||
|         c.CURLM_ABORTED_BY_CALLBACK => Multi.AbortedByCallback, | ||||
|         c.CURLM_UNRECOVERABLE_POLL => Multi.UnrecoverablePoll, | ||||
|         else => Multi.Unknown, | ||||
|     }; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Karl Seguin
					Karl Seguin