get_s等secure functions的使用

安全使用gets_s与getws_s函数
本文详细介绍了gets_s和getws_s函数的安全使用方法。这些函数用于从标准输入流读取一行文本,相较于传统的gets函数,它们在内部实现了更安全的缓冲区管理机制。文章还解释了如何正确指定缓冲区大小以及如何处理输入长度超过缓冲区容量的情况。

_s类函数的使用策略

首先介绍下gets_s、getws_s函数的用法。gets_s, _getws_s
https://msdn.microsoft.com/en-us/library/5b5x9wc7.aspx

Gets a line from the stdin stream. These versions of gets, _getws have security enhancements(安全加强), as described in Security Features in the CRT.

char *gets_s(
   char *buffer,
   size_t sizeInCharacters
);
wchar_t *_getws_s(
   wchar_t *buffer,
   size_t sizeInCharacters
);
template <size_t size>
char *gets_s(
   char (&buffer)[size]    //指针的引用类型,可以避免在函数参数传递中数组被退化成指针
); // C++ only
template <size_t size>
wchar_t *_getws_s(
   wchar_t (&buffer)[size]
); // C++ only

Parameters

[out] buffer

Storage location for input string.

[in] sizeInCharacters   note:这里是用字符数表示的尺寸,而非字节数。

The size of the buffer.

Return Value

Returns buffer if successful. A NULL pointer indicates an error or end-of-file condition. Use ferror or feof to determine which one has occurred.   note:返回值可不是接收了多少字符,而是buffer指针。

Remarks

The gets_s function reads a line from the standard input stream stdin and stores it in buffer. The line consists of all characters up to and including the first newline character ('\n'). gets_s then replaces the newline character with a null character ('\0') before returning the line. In contrast, the fgets_s function retains(保留) the newline character.

总结:gets_s在读取一行时,贴心为我们处理了换行符,并且知道我们一般不想要这个换行,将它顺势换成了终止符’\0’(note:为什么live writer

If the first character read is the end-of-file character, a null character is stored at the beginning of buffer and NULL is returned.

_getws is a wide-character version of gets_s; its argument and return value are wide-character strings.

If buffer is NULL or sizeInCharacters is less than or equal to zero, or if the buffer is too small to contain the input line and null terminator, these functions invoke an invalid parameter handler, as described in Parameter Validation. If execution is allowed to continue, these functions return NULL and set errno to ERANGE.

In C++, using these functions is simplified by template overloads; the overloads can infer buffer length automatically (eliminating the need to specify a size argument) and they can automatically replace older, non-secure functions with their newer, secure counterparts. For more information, see Secure Template Overloads.

顺便说一下,scanf与scanf_s、gets与gets_s(note:这里的gets_s里的第一个s表示string即字符串,第二个表示safe)、以及这里的fopen_s和fopen,之所以说带_s的函数安全,并不是说在在用户输入超过缓冲区长度时不报错,而是正好相反,在检测到缓冲区不够时,一定会报错。

From Security Features in the CRT   https://msdn.microsoft.com/en-us/library/8ef0s5kh.aspx

The secure functions do not prevent or correct security errors; rather(而是), they catch errors when they occur. They perform additional checks for error conditions, and in the case of an error, they invoke an error handler (see Parameter Validation).

不会像scanf接收字符到一个char数组里,如果用户输入的字符数超过了缓冲区的长度时,scanf也可能“一声不吭”(注:在一些编译器下,确实会存在这种情况),这种做法在一段时间内可能不会产生什么异常,但是操作不属于自己的内存空间,这本身就是一个漏洞,即所谓的“缓冲区溢出漏洞”,经常被一些黑客利用。想想如果这些被误操作的字节,正好对应一个关键数据,或者是对应一个函数的入口地址注:这种情况下,黑客可以利用缓冲区溢出漏洞将这个入口地址改为它自己编写的木马程序的入口地址。你就悲剧了!纯粹道听途说,自己没试过!!)

》》》可能有些同学对gets_s在接收到超过缓冲区长度的数据时的弹出错误或警告窗体的做法表示不解,其实我的心里是想让按下面方式行事。

一、当用户输入的数据的长度(注:到底指什么要搞清楚)不超过缓冲区长度时,正常接收换行符前的所有字符。

(note:如果不注意的话,这里又是一个pitfall,当然前提是你在使用gets_s时,输入中既有中文,又有英文等西方字符,后面写一篇关于接收单字节字符和宽字符的区别的日志。对于实用程序应该始终使用w_char)。

二、当用户的输入的数据的长度超过缓冲区长度时,接收“第二个参数的值减一”个字符,并将缓冲区最后一个字符设置为终止符。(ASK:宽字符中的终止符是什么样的?两个字节的全0吗?)。

对于我们的第二条愿望,标准库中的默认实现一般会是报错提醒,但是真正的实用的应用程序,用户不会允许自己使用的软件动不动就报错,暂且不讨论有多少用户会使用从控制台接收输入的软件。实际上这也是可以实现的。

From Parameter Validation https://msdn.microsoft.com/en-us/library/ksazx244.aspx

Most of the security-enhanced CRT(C运行时) functions and many of the preexisting(先前存在的) functions validate their parameters. This could include checking pointers for NULL, checking that integers fall into a valid range, or checking that enumeration values are valid. When an invalid parameter is found, the invalid parameter handler is executed.
note:注意这时提到一些验证参数的例子,翻译如下:
一、指针是否为空。
二、整型是否会落入一个有效的范围。
三、检查枚举类型是否有效。
而且如果一个无效的参数被发现,会执行相应的无效参数处理机制。???是每一种类型的参数异常对应一种处理机制吗?

Invalid Parameter Handler Routine
--------------------------------------------------------------------------------
The behavior of the C Runtime when an invalid parameter is found is to call the currently assigned invalid parameter handler. The default(note:这里应该指的是运行时,而不是调试时) invalid parameter invokes Watson crash reporting, which causes the application to crash and asks the user if they want to load the crash dump to Microsoft for analysis. In Debug mode, an invalid parameter also results in a failed assertion.如下图所示,是gets_s函数接收的用户输入超过缓冲区长度时的警告窗口。

image_thumb[8]

This behavior can be changed by using the function _set_invalid_parameter_handler to set the invalid parameter handler to your own function.(note:你可以通过set_invalid_parameter_handler 函数来设定无效参数 的处理机制到你自己定义的函数) If the function you specify does not terminate the application, control is returned to the function that received the invalid parameters, and these functions will normally cease execution, return an error code(note:这个收到无效参数的函数会正常地结束执行,并返回一个错误码。注意反省一下,自己在处理相应的问题时,对于非法输入是都能返回相应的错误码。ASK:在编程时如何利用函数返回值和errno值????), and set errno to an error code. In many cases, the errno value and the return value are both EINVAL, indicating an invalid parameter. In some cases, a more specific error code is returned, such as EBADF for a bad file pointer passed in as a parameter. For more information on errno, see errno, _doserrno, _sys_errlist, and _sys_nerr.
==========

转载于:https://my.oschina.net/ray1421/blog/704399

/** copyright Copyright © 2009-2025 Shenzhen TP-LINK Technologies Co.Ltd. file mult_plex_web.h brief Multi-plex implementation of httpd author An Ran anran@tp-link.com.hk version 1.0.0 date 14Aug25 */ // /* INCLUDE FILES */ // #include “mult_plex_web.h” // /* DEFINES */ // // /* TYPES */ // // /* EXTERN_PROTOTYPES */ // // /* LOCAL_PROTOTYPES */ // // /* VARIABLES */ // // /* LOCAL_FUNCTIONS */ // /** fn static int check_http_method(const char *buffer) brief Check if the HTTP request method is supported param[in] const char *buffer return 0 Other method, 1 Get method, 2 Post method note */ static int check_http_method(const char buffer) { if (0 == strncmp(buffer, "GET ", 4)) { / Get method / return 1; } else if (0 == strncmp(buffer, "POST ", 5)) { / Post method / return 2; } else { / Other method */ return 0; } } /** fn static void send_headers(int client_socket, int status, const char *status_msg, const char *content_type, long content_length) brief Send HTTP response headers param[in] client_socket Socket descriptor status HTTP status code status_msg The text description corresponding to the status code content_type The MIME type of the response content content_length The length of the bytes in the response body note */ void send_headers(int client_socket, int status, const char *status_msg, const char content_type, long content_length) { / Buffer */ char headers[BUFFER_SIZE]; snprintf(headers, sizeof(headers), “HTTP/1.1 %d %s\r\n” “Server: Simple-C-WebServer\r\n” “Content-Type: %s\r\n” “Content-Length: %ld\r\n” “Connection: close\r\n” “\r\n”, status, status_msg, content_type, content_length); send(client_socket, headers, strlen(headers), 0); } /** fn static void send_error(int client_socket, int status, const char *status_msg, const char *message) brief Send an error response param[in] client_socket Socket descriptor status HTTP status code status_msg The text description corresponding to the status code content_type Customize error details note */ void send_error(int client_socket, int status, const char *status_msg, const char message) { / Buffer */ char response[BUFFER_SIZE]; /* Records the number of bytes that have been written to the buffer at the moment*/ int length = 0; length = snprintf(response, sizeof(response), “%d %s” “ %d %s %s ”, status, status_msg, status, status_msg, message); send_headers(client_socket, status, status_msg, “text/html”, length); send(client_socket, response, length, 0); } /** fn static const char *get_mime_type(const char *filename) brief Get the MIME type of the file param[in] filename Full file name or file path note */ static const char *get_mime_type(const char filename) { / A pointer to the starting position of the extension in the file name */ const char *ext = strrchr(filename, ‘.’); if (!ext) { return “application/octet-stream”; } if (strcmp(ext, “.html”) == 0 || strcmp(ext, “.htm”) == 0) { return “text/html”; } if (strcmp(ext, “.txt”) == 0) { return “text/plain”; } if (strcmp(ext, “.css”) == 0) { return “text/css”; } if (strcmp(ext, “.js”) == 0) { return “application/javascript”; } if (strcmp(ext, “.jpg”) == 0 || strcmp(ext, “.jpeg”) == 0) { return “image/jpeg”; } if (strcmp(ext, “.png”) == 0) { return “image/png”; } if (strcmp(ext, “.gif”) == 0) { return “image/gif”; } if (strcmp(ext, “.pdf”) == 0) { return “application/pdf”; } if (strcmp(ext, “.zip”) == 0) { return “application/zip”; } return “application/octet-stream”; } /** fn static void send_file(int client_socket, const char *filename) brief Send the file content param[in] client_socket Socket descriptor filename The requested file path note / static void send_file(int client_socket, const char filename) { / file_stat Store file metadata dir A directory flow pointer that is used to iterate \ through the contents of the catalog response HTML response buffer entry Catalog entry information length Records the number of bytes that have been \ written to the buffer at the moment path Temporarily stores the full path to the directory entry entry_stat Stores the metadata of individual files within a directory size_str File size formatting string fd File descriptor buffer File read/write buffer bytes_read Records the number of bytes per read() read */ struct stat file_stat = {0}; struct stat entry_stat = {0}; char response[BUFFER_SIZE * 4]; char path[PATH_MAX] = {0}; char buffer[BUFFER_SIZE]; char size_str[20] = {0}; int length = 0; int fd = -1; ssize_t bytes_read = 0; DIR *dir = NULL; const char *mime_type = NULL; struct dirent *entry = NULL; if (0 > stat(filename, &file_stat)) { send_error(client_socket, 404, “Not Found”, “File not found”); return; } if (S_ISDIR(file_stat.st_mode)) { /* If it’s a catalog, list the contents of the catalog */ dir = opendir(filename); if (!dir) { send_error(client_socket, 403, “Forbidden”, “Cannot list directory”); return; } length = snprintf(response, sizeof(response), “Index of %s” “ Index of %s ”, filename, filename); while (NULL != (entry = readdir(dir))) { /* Skip hidden files and current/parent directories */ if (‘.’ == entry->d_name[0]) { continue; } snprintf(path, sizeof(path), “%s/%s”, filename, entry->d_name); stat(path, &entry_stat); if (S_ISDIR(entry_stat.st_mode)) { strcpy(size_str, “<DIR>”); } else { snprintf(size_str, sizeof(size_str), “%ld bytes”, entry_stat.st_size); } length += snprintf(response + length, sizeof(response) - length, “ <a href="%s">%s - %s”, entry->d_name, entry->d_name, size_str); } length += snprintf(response + length, sizeof(response) - length, “”); closedir(dir); send_headers(client_socket, 200, “OK”, “text/html”, length); send(client_socket, response, length, 0); return; } /* Send the file content */ fd = open(filename, O_RDONLY); if (0 > fd) { send_error(client_socket, 403, “Forbidden”, “Cannot open file”); return; } /* Send HTTP headers */ mime_type = get_mime_type(filename); send_headers(client_socket, 200, “OK”, mime_type, file_stat.st_size); /* Send the file content */ while (0 < (bytes_read = read(fd, buffer, sizeof(buffer)))) { send(client_socket, buffer, bytes_read, 0); } close(fd); } /** fn static void url_decode(const char *src, char *dest, size_t dest_size) brief URL decoding param[in] src Temporarily store the original path dest Stores the decoded string dest_size Store the space size of the decoded string param[out] dest Stores the decoded string note */ static void url_decode(const char *src, char dest, size_t dest_size) { / Space maximum */ char *end = dest + dest_size - 1; while (*src && dest < end) { if (*src == ‘%’ && isxdigit(src[1]) && isxdigit(src[2])) { char hex[3] = {src[1], src[2], ‘\0’}; *dest++ = (char)strtol(hex, NULL, 16); src += 3; } else if (*src == ‘+’) { *dest++ = ’ '; src++; } else { *dest++ = *src++; } } *dest = ‘\0’; } /** fn static int parse_request_path(const char *buffer, char *decoded_path, size_t decoded_size) brief Check the path format and URL process param[in] buffer Received data buffer decoded_path Stores the decoded string decoded_size Store the space size of the decoded string note */ static int parse_request_path(const char *buffer, char decoded_path, size_t decoded_size) { / Temporarily store the original path and path length */ char raw_path[BUFFER_SIZE]; size_t path_len; /* Skip the "GET " */ const char *path_start = buffer + 4; /* Check if the path in the HTTP header is formatted correctly */ const char *path_end = strchr(path_start, ’ '); if (!path_end) { return -1; } /* Temporarily store the original path */ path_len = path_end - path_start; if (path_len >= sizeof(raw_path)) { return -1; } memcpy(raw_path, path_start, path_len); raw_path[path_len] = ‘\0’; /* URL decoding */ url_decode(raw_path, decoded_path, decoded_size); return 0; } /** fn static int build_safe_path(const char *root_dir, const char *decoded_path, char *full_path, size_t full_path_size) brief Build a secure output directory param[in] root_dir Root path decoded_path Stores the decoded string full_path The full path of the output full_path_size Buffer size note */ static int build_safe_path(const char *root_dir, const char *decoded_path, char full_path, size_t full_path_size) { / Prevent directory traversal attacks */ if (strstr(decoded_path, “…”)) { return -1; } snprintf(full_path, full_path_size, “%s%s”, root_dir, decoded_path); /* Automatically add Index.html */ if (full_path[strlen(full_path) - 1] == ‘/’) { strncat(full_path, “Index.html”, full_path_size - strlen(full_path) - 1); } return 0; } /** fn static void handle_get_request(int client_socket, char *buffer) brief Process GET requests param[in] client_socket client socket buffer Received data buffer note */ static void handle_get_request(int client_socket, char buffer) { / *decoded_path Stores the decoded string *full_path The full path of the output */ char decoded_path[BUFFER_SIZE]; char full_path[BUFFER_SIZE]; /* URL process */ if (0 != parse_request_path(buffer, decoded_path, sizeof(decoded_path))) { send_error(client_socket, 400, “Bad Request”, “Invalid request”); return; } /* Build a safe path */ if (0 != build_safe_path(ROOT_DIR, decoded_path, full_path, sizeof(full_path))) { send_error(client_socket, 403, “Forbidden”, “Directory traversal not allowed”); return; } /* Send files */ printf(“Request: %s -> %s\n”, decoded_path, full_path); send_file(client_socket, full_path); return; } /** fn static void handle_post_request(int client_socket, char *buffer, ssize_t bytes_read) brief Process POST requests param[in] client_socket client socket buffer Received data buffer bytes_read Received data length note */ static void handle_post_request(int client_socket, char *buffer, ssize_t bytes_read) { /** content_length_start Look for the “Content-Length” field in the HTTP response header body_start Look for the “Message body” field in the HTTP response header post_data Stored the post data response Respond to messages total_read copy the length of the data has been read content_length Expected message body length body_len Actual message body length n The size of the bytes read */ char *content_length_start = NULL; char *body_start = NULL; char *post_data = NULL; const char *response = NULL; int total_read = 0; int content_length = 0; int body_len = 0; int n = 0; /* get Content-Length */ content_length_start = strstr(buffer, "Content-Length: "); if (!content_length_start) { perror(“get Content-Length failed”); exit(EXIT_FAILURE); } /* skip "Content-Length: "*/ content_length_start += 16; content_length = atoi(content_length_start); /* read POST data */ post_data = malloc(content_length + 1); if (!post_data) { perror(“get POST data failed”); exit(EXIT_FAILURE); } body_start = strstr(buffer, “\r\n\r\n”); /* Copy the data in the buffer to your local location */ if (body_start) { body_start += 4; body_len = bytes_read - (body_start - buffer); memcpy(post_data, body_start, body_len); total_read = body_len; } /* Read the remaining data */ while (total_read < content_length) { n = recv(client_socket, post_data + total_read, content_length - total_read, 0); if (n <= 0) { break; } total_read += n; } post_data[total_read] = ‘\0’; /* Print the POST data */ printf(“Received POST data: %s\n”, post_data); /* Send the response */ response = “{“callback”:“congratulations!”}”; send_headers(client_socket, 200, “OK”, “application/json”, strlen(response)); send(client_socket, response, strlen(response), 0); free(post_data); } // /* PUBLIC_FUNCTIONS / // /* fn void handle_request(int client_socket) brief Handle HTTP requests param[in] int client_socket Socket file descriptor note / void handle_request(int client_socket) { / *buffer Stores the decoded string *bytes_read Received data length *method Method type */ char buffer[BUFFER_SIZE]; int method = 0; ssize_t bytes_read = recv(client_socket, buffer, sizeof(buffer) - 1, 0); /* Receive data fails to be handled */ if (0 >= bytes_read) { return; } buffer[bytes_read] = ‘\0’; /* Check the HTTP method / method = check_http_method(buffer); if (0 == method) { send_error(client_socket, 501, “Not Implemented”, “Only GET and POST methods are supported”); return; } else if (1 == method ) { / Process GET requests / handle_get_request(client_socket, buffer); return; } else if (2 == method) { / Process POST requests */ handle_post_request(client_socket, buffer, bytes_read); return; } } // /* GLOBAL_FUNCTIONS */ // int main() { /** server_socket The server listens to the socket opt Socket option value server_addr Server address information max_ser_socket */ int server_socket = -1; int opt = 1; struct sockaddr_in server_addr; int max_ser_socket = -1; fd_set rdset, rdtmp; FD_ZERO(&rdset); /* Create a server socket / server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket < 0) { perror(“socket creation failed”); exit(EXIT_FAILURE); } / Set SO_REUSEADDR options / if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror(“setsockopt failed”); close(server_socket); exit(EXIT_FAILURE); } / Bind addresses and ports / memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (0 > bind(server_socket, (struct sockaddr )&server_addr, sizeof(server_addr)) ) { perror(“bind failed”); close(server_socket); exit(EXIT_FAILURE); } / Start listening / if (0 > listen(server_socket, BACKLOG)) { perror(“listen failed”); close(server_socket); exit(EXIT_FAILURE); } printf(“Server running on port %d, serving files from %s\n”, PORT, ROOT_DIR); printf(“Open http://localhost in your browser\n”); max_ser_socket = server_socket; FD_SET(server_socket, &rdset); / Main loop: Accept and process connections / while (1) { / * client_addr Stores the client’s address information * client_addr_len Used to store the length of client_addr structure * client_socket Store the socket descriptor of the client * fd Traverse the file descriptor collection / int fd = 0; struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_socket = -1; / A copy of rdset (a collection of read file descriptors). / rdtmp = rdset; / Call select listens for file descriptors in the rdtmp collection / select(max_ser_socket + 1, &rdtmp, NULL, NULL, NULL); / Loop through each file descriptor from 0 to max_ser_socket / for (; fd < max_ser_socket + 1; fd++) { / There is a reading event / if (FD_ISSET(fd, &rdtmp)) { / New connections / if (fd == server_socket) { / Accept the connection */ client_socket = accept(server_socket, (struct sockaddr )&client_addr, &client_addr_len); if (0 > client_socket) { perror(“accept failed!”); close(client_socket); continue; } / Add the new client socket and update the max_ser_socket / FD_SET(client_socket, &rdset); max_ser_socket = client_socket > max_ser_socket ? client_socket : max_ser_socket; } else { / Connected clients */ handle_request(fd); close(fd); FD_CLR(fd, &rdset); } } } } close(server_socket); return 0; }给我生成一个以上代码的设计流程图,要抽象出来实现的功能方法和目的
08-15
PS C:\Users\10556> C:/mini/Scripts/activate PS C:\Users\10556> conda activate QR-env PS C:\Users\10556> & C:/mini/envs/QR-env/python.exe d:/wenxvn/CylinderImageProcessing/QReader-main/pyzbar_opencv_comparison.py d:/wenxvn/CylinderImageProcessing/QReader-main/pyzbar_opencv_comparison.py:15: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature. detector_model = torch.load(buffer, map_location=torch.device('cpu')) C:\mini\envs\QR-env\lib\site-packages\qrdet\qrdet.py:129: UserWarning: QRDetector has been updated to use the new YoloV8 model. Use legacy=True when calling detect for backwards compatibility with 1.x versions. Or update to new output (new output is a tuple of dicts, containing several new information (1.x output is accessible through 'bbox_xyxy' and 'confidence').Forget this message if you are reading it from QReader. [This is a first download warning and will be removed at 2.1] warn("QRDetector has been updated to use the new YoloV8 model. Use legacy=True when calling detect " Traceback (most recent call last): File "C:\mini\envs\QR-env\lib\site-packages\urllib3\connectionpool.py", line 466, in _make_request self._validate_conn(conn) File "C:\mini\envs\QR-env\lib\site-packages\urllib3\connectionpool.py", line 1095, in _validate_conn conn.connect() File "C:\mini\envs\QR-env\lib\site-packages\urllib3\connection.py", line 730, in connect sock_and_verified = _ssl_wrap_socket_and_match_hostname( File "C:\mini\envs\QR-env\lib\site-packages\urllib3\connection.py", line 909, in _ssl_wrap_socket_and_match_hostname ssl_sock = ssl_wrap_socket( File "C:\mini\envs\QR-env\lib\site-packages\urllib3\util\ssl_.py", line 469, in ssl_wrap_socket ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname) File "C:\mini\envs\QR-env\lib\site-packages\urllib3\util\ssl_.py", line 513, in _ssl_wrap_socket_impl return ssl_context.wrap_socket(sock, server_hostname=server_hostname) File "C:\mini\envs\QR-env\lib\ssl.py", line 500, in wrap_socket return self.sslsocket_class._create( File "C:\mini\envs\QR-env\lib\ssl.py", line 1073, in _create self.do_handshake() File "C:\mini\envs\QR-env\lib\ssl.py", line 1342, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1149) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "C:\mini\envs\QR-env\lib\site-packages\urllib3\connectionpool.py", line 789, in urlopen response = self._make_request( File "C:\mini\envs\QR-env\lib\site-packages\urllib3\connectionpool.py", line 490, in _make_request raise new_e urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1149) The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\mini\envs\QR-env\lib\site-packages\requests\adapters.py", line 667, in send resp = conn.urlopen( File "C:\mini\envs\QR-env\lib\site-packages\urllib3\connectionpool.py", line 843, in urlopen retries = retries.increment( File "C:\mini\envs\QR-env\lib\site-packages\urllib3\util\retry.py", line 519, in increment raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type] urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='github.com', port=443): Max retries exceeded with url: /Eric-Canas/qrdet/releases/download/v2.0_release/qrdet-s.pt (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1149)'))) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "d:/wenxvn/CylinderImageProcessing/QReader-main/pyzbar_opencv_comparison.py", line 31, in <module> qreader_reader = load_model_secure(SECURE_MODEL_PATH) File "d:/wenxvn/CylinderImageProcessing/QReader-main/pyzbar_opencv_comparison.py", line 17, in load_model_secure qreader = QReader(model_size='s') File "d:\wenxvn\cylinderimageprocessing\qreader-main\src\qreader\__init__.py", line 109, in __init__ self.detector = QRDetector(model_size=model_size, conf_th=min_confidence) File "C:\mini\envs\QR-env\lib\site-packages\qrdet\qrdet.py", line 46, in __init__ path = self.__download_weights_or_return_path(model_size=model_size) File "C:\mini\envs\QR-env\lib\site-packages\qrdet\qrdet.py", line 133, in __download_weights_or_return_path response = requests.get(url, stream=True) File "C:\mini\envs\QR-env\lib\site-packages\requests\api.py", line 73, in get return request("get", url, params=params, **kwargs) File "C:\mini\envs\QR-env\lib\site-packages\requests\api.py", line 59, in request return session.request(method=method, url=url, **kwargs) File "C:\mini\envs\QR-env\lib\site-packages\requests\sessions.py", line 589, in request resp = self.send(prep, **send_kwargs) File "C:\mini\envs\QR-env\lib\site-packages\requests\sessions.py", line 703, in send r = adapter.send(request, **kwargs) File "C:\mini\envs\QR-env\lib\site-packages\requests\adapters.py", line 698, in send raise SSLError(e, request=request) requests.exceptions.SSLError: HTTPSConnectionPool(host='github.com', port=443): Max retries exceeded with url: /Eric-Canas/qrdet/releases/download/v2.0_release/qrdet-s.pt (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1149)'))) PS C:\Users\10556>
最新发布
08-19
/** * copyright Copyright (c) 2009-2025 Shenzhen TP-LINK Technologies Co.Ltd. * * file mult_thread_web.c * brief * * author An Ran <anran@tp-link.com.hk> * version 1.0.0 * date 08Aug25 * * history \arg, 1.0.0, 08Aug25, An Ran, Create the file */ /**************************************************************************************************/ /* INCLUDE FILES */ /**************************************************************************************************/ #include "mult_thread_web.h" /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* EXTERN_PROTOTYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_PROTOTYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* VARIABLES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_FUNCTIONS */ /**************************************************************************************************/ /** * fn static void send_headers(int client_socket, int status, const char *status_msg, const char *content_type, long content_length) * brief Send HTTP response headers * * param[in] client_socket Socket descriptor * status HTTP status code * status_msg The text description corresponding to the status code * content_type The MIME type of the response content * content_length The length of the bytes in the response body * * note */ static void send_headers(int client_socket, int status, const char *status_msg, const char *content_type, long content_length) { char headers[BUFFER_SIZE]; snprintf(headers, sizeof(headers), "HTTP/1.1 %d %s\r\n" "Server: Simple-C-WebServer\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "Connection: close\r\n" "\r\n", status, status_msg, content_type, content_length); send(client_socket, headers, strlen(headers), 0); } /** * fn static void send_error(int client_socket, int status, * const char *status_msg, const char *message) * brief Send an error response * * param[in] client_socket Socket descriptor * status HTTP status code * status_msg The text description corresponding to the status code * content_type Customize error details * * note */ static void send_error(int client_socket, int status, const char *status_msg, const char *message) { /* Buffer */ char response[BUFFER_SIZE]; /* Records the number of bytes that have been written to the buffer at the moment*/ int length = 0; length = snprintf(response, sizeof(response), "<html><head><title>%d %s</title></head>" "<body><h1>%d %s</h1><p>%s</p></body></html>", status, status_msg, status, status_msg, message); send_headers(client_socket, status, status_msg, "text/html", length); send(client_socket, response, length, 0); } // 获取文件MIME类型 /** * fn static const char *get_mime_type(const char *filename) * brief Get the MIME type of the file * * param[in] filename Full file name or file path * * note */ static const char *get_mime_type(const char *filename) { /* A pointer to the starting position of the extension in the file name */ const char *ext = strrchr(filename, '.'); if (!ext) { return "application/octet-stream"; } if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) { return "text/html"; } if (strcmp(ext, ".txt") == 0) { return "text/plain"; } if (strcmp(ext, ".css") == 0) { return "text/css"; } if (strcmp(ext, ".js") == 0) { return "application/javascript"; } if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) { return "image/jpeg"; } if (strcmp(ext, ".png") == 0) { return "image/png"; } if (strcmp(ext, ".gif") == 0) { return "image/gif"; } if (strcmp(ext, ".pdf") == 0) { return "application/pdf"; } if (strcmp(ext, ".zip") == 0) { return "application/zip"; } return "application/octet-stream"; } /** * fn static void send_file(int client_socket, const char *filename) * brief Send the file content * * param[in] client_socket Socket descriptor * filename The requested file path * note */ static void send_file(int client_socket, const char *filename) { /** * file_stat Store file metadata * dir A directory flow pointer that is used to iterate \ * through the contents of the catalog * response HTML response buffer * entry Catalog entry information * length Records the number of bytes that have been \ * written to the buffer at the moment * path Temporarily stores the full path to the directory entry * entry_stat Stores the metadata of individual files within a directory * size_str File size formatting string * fd File descriptor * buffer File read/write buffer * bytes_read Records the number of bytes per read() read */ struct stat file_stat = {0}; struct stat entry_stat = {0}; char response[BUFFER_SIZE * 4]; char path[PATH_MAX] = {0}; char buffer[BUFFER_SIZE]; char size_str[20] = {0}; int length = 0; int fd = -1; ssize_t bytes_read = 0; DIR *dir = NULL; const char *mime_type = NULL; struct dirent *entry = NULL; if (0 > stat(filename, &file_stat)) { send_error(client_socket, 404, "Not Found", "File not found"); return; } if (S_ISDIR(file_stat.st_mode)) { /* If it's a catalog, list the contents of the catalog */ dir = opendir(filename); if (!dir) { send_error(client_socket, 403, "Forbidden", "Cannot list directory"); return; } length = snprintf(response, sizeof(response), "<html><head><title>Index of %s</title></head>" "<body><h1>Index of %s</h1><ul>", filename, filename); while (NULL != (entry = readdir(dir))) { /* Skip hidden files and current/parent directories */ if ('.' == entry->d_name[0]) { continue; } snprintf(path, sizeof(path), "%s/%s", filename, entry->d_name); stat(path, &entry_stat); if (S_ISDIR(entry_stat.st_mode)) { strcpy(size_str, "<DIR>"); } else { snprintf(size_str, sizeof(size_str), "%ld bytes", entry_stat.st_size); } length += snprintf(response + length, sizeof(response) - length, "<li><a href=\"%s\">%s</a> - %s</li>", entry->d_name, entry->d_name, size_str); } length += snprintf(response + length, sizeof(response) - length, "</ul></body></html>"); closedir(dir); send_headers(client_socket, 200, "OK", "text/html", length); send(client_socket, response, length, 0); return; } /* Send the file content */ fd = open(filename, O_RDONLY); if (0 > fd) { send_error(client_socket, 403, "Forbidden", "Cannot open file"); return; } /* Send HTTP headers */ mime_type = get_mime_type(filename); send_headers(client_socket, 200, "OK", mime_type, file_stat.st_size); /* Send the file content */ while (0 < (bytes_read = read(fd, buffer, sizeof(buffer)))) { send(client_socket, buffer, bytes_read, 0); } close(fd); } /** * fn static int check_http_method(const char *buffer) * brief Check if the HTTP request method is supported * * param[in] const char *buffer * * return 0 Other method, 1 Get method, 2 Post method * * note */ static int check_http_method(const char *buffer) { if (0 == strncmp(buffer, "GET ", 4)) { /* Get method */ return 1; } else if (0 == strncmp(buffer, "POST ", 5)) { /* Post method */ return 2; } else { /* Other method */ return 0; } } /** * fn static void url_decode(const char *src, char *dest, size_t dest_size) * brief URL decoding * * param[in] src Temporarily store the original path * dest Stores the decoded string * dest_size Store the space size of the decoded string * param[out] dest Stores the decoded string * * note */ static void url_decode(const char *src, char *dest, size_t dest_size) { /* Space maximum */ char *end = dest + dest_size - 1; while (*src && dest < end) { if (*src == '%' && isxdigit(src[1]) && isxdigit(src[2])) { char hex[3] = {src[1], src[2], '\0'}; *dest++ = (char)strtol(hex, NULL, 16); src += 3; } else if (*src == '+') { *dest++ = ' '; src++; } else { *dest++ = *src++; } } *dest = '\0'; } /** * fn static int parse_request_path(const char *buffer, * char *decoded_path, size_t decoded_size) * brief Check the path format and URL process * * param[in] buffer Received data buffer * decoded_path Stores the decoded string * decoded_size Store the space size of the decoded string * * note */ static int parse_request_path(const char *buffer, char *decoded_path, size_t decoded_size) { /* Temporarily store the original path and path length */ char raw_path[BUFFER_SIZE]; size_t path_len; /* Skip the "GET " */ const char *path_start = buffer + 4; /* Check if the path in the HTTP header is formatted correctly */ const char *path_end = strchr(path_start, ' '); if (!path_end) { return -1; } /* Temporarily store the original path */ path_len = path_end - path_start; if (path_len >= sizeof(raw_path)) { return -1; } memcpy(raw_path, path_start, path_len); raw_path[path_len] = '\0'; /* URL decoding */ url_decode(raw_path, decoded_path, decoded_size); return 0; } /** * fn static int build_safe_path(const char *root_dir, const char *decoded_path, char *full_path, size_t full_path_size) * brief Build a secure output directory * * param[in] root_dir Root path * decoded_path Stores the decoded string * full_path The full path of the output * full_path_size Buffer size * * note */ static int build_safe_path(const char *root_dir, const char *decoded_path, char *full_path, size_t full_path_size) { /* Prevent directory traversal attacks */ if (strstr(decoded_path, "..")) { return -1; } snprintf(full_path, full_path_size, "%s%s", root_dir, decoded_path); /* Automatically add index.html */ if (full_path[strlen(full_path) - 1] == '/') { strncat(full_path, "index.html", full_path_size - strlen(full_path) - 1); } return 0; } /** * fn static void handle_get_request(int client_socket, char *buffer) * brief Process GET requests * * param[in] client_socket client socket * buffer Received data buffer * * note */ static void handle_get_request(int client_socket, char *buffer) { /* *decoded_path Stores the decoded string *full_path The full path of the output */ char decoded_path[BUFFER_SIZE]; char full_path[BUFFER_SIZE]; /* URL process */ if (0 != parse_request_path(buffer, decoded_path, sizeof(decoded_path))) { send_error(client_socket, 400, "Bad Request", "Invalid request"); return; } /* Build a safe path */ if (0 != build_safe_path(ROOT_DIR, decoded_path, full_path, sizeof(full_path))) { send_error(client_socket, 403, "Forbidden", "Directory traversal not allowed"); return; } /* Send files */ printf("Request: %s -> %s\n", decoded_path, full_path); send_file(client_socket, full_path); return; } /** * fn static void handle_post_request(int client_socket, char *buffer, ssize_t bytes_read) * brief Process POST requests * * param[in] client_socket client socket * buffer Received data buffer * bytes_read Received data length * * note */ static void handle_post_request(int client_socket, char *buffer, ssize_t bytes_read) { /** * content_length_start Look for the "Content-Length" field in the HTTP response header * body_start Look for the "Message body" field in the HTTP response header * post_data Stored the post data * response Respond to messages * total_read copy the length of the data has been read * content_length Expected message body length * body_len Actual message body length * n The size of the bytes read */ char *content_length_start = NULL; char *body_start = NULL; char *post_data = NULL; const char *response = NULL; int total_read = 0; int content_length = 0; int body_len = 0; int n = 0; /* get Content-Length */ content_length_start = strstr(buffer, "Content-Length: "); if (!content_length_start) { return; } /* skip "Content-Length: "*/ content_length_start += 16; content_length = atoi(content_length_start); /* read POST data */ post_data = malloc(content_length + 1); if (!post_data) { return; } body_start = strstr(buffer, "\r\n\r\n"); /* Copy the data in the buffer to your local location */ if (body_start) { body_start += 4; body_len = bytes_read - (body_start - buffer); memcpy(post_data, body_start, body_len); total_read = body_len; } /* Read the remaining data */ while (total_read < content_length) { n = recv(client_socket, post_data + total_read, content_length - total_read, 0); if (n <= 0) break; total_read += n; } post_data[total_read] = '\0'; /* Print the POST data */ printf("Received POST data: %s\n", post_data); /* Send the response */ response = "{\"callback\":\"congratulations!\"}"; send_headers(client_socket, 200, "OK", "application/json", strlen(response)); send(client_socket, response, strlen(response), 0); free(post_data); } /**************************************************************************************************/ /* PUBLIC_FUNCTIONS */ /**************************************************************************************************/ /** * fn void *handle_request(void *argv) * brief Handle HTTP requests * * param[in] void *argv Socket file descriptor * * note */ void *handle_request(void *argv) { /* *buffer Stores the decoded string *client_socket Socket descriptor *bytes_read Received data length *method Method type */ char buffer[BUFFER_SIZE]; int client_socket = *((int *)argv); int method = 0; ssize_t bytes_read = recv(client_socket, buffer, sizeof(buffer) - 1, 0); /* Receive data fails to be handled */ if (0 >= bytes_read) { close(client_socket); return NULL; } buffer[bytes_read] = '\0'; /* Check the HTTP method */ method = check_http_method(buffer); if (0 == method) { send_error(client_socket, 501, "Not Implemented", "Only GET and POST methods are supported"); close(client_socket); return NULL; } else if (1 == method ) { /* Process POST requests */ handle_post_request(client_socket, buffer, bytes_read); close(client_socket); return NULL; } else if (2 == method) { /* Process GET requests */ handle_get_request(client_socket, buffer); close(client_socket); return NULL; } return NULL; } /**************************************************************************************************/ /* GLOBAL_FUNCTIONS */ /**************************************************************************************************/ int main() { /** * server_socket The server listens to the socket * opt Socket option value * server_addr Server address information */ int server_socket = -1; int opt = 1; struct sockaddr_in server_addr; /* Create a server socket */ server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } /* Set SO_REUSEADDR options */ if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror("setsockopt failed"); close(server_socket); exit(EXIT_FAILURE); } /* Bind addresses and ports */ memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (0 > bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr))) { perror("bind failed"); close(server_socket); exit(EXIT_FAILURE); } /* Start listening */ if (0 > listen(server_socket, BACKLOG)) { perror("listen failed"); close(server_socket); exit(EXIT_FAILURE); } printf("Server running on port %d, serving files from %s\n", PORT, ROOT_DIR); printf("Open http://localhost in your browser\n"); /* Main loop: Accept and process connections */ while (1) { struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int *client_socket = malloc(sizeof(int)); pthread_t tid; if (!client_socket) { /* Legality check */ perror("malloc failed!"); free(client_socket); continue; } *client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len); if (0 > *client_socket) { perror("accept failed"); continue; } /* Create a new thread to process the request */ if (0 != pthread_create(&tid, NULL, handle_request, (void *)client_socket)) { /* Legality check */ perror("pthread failed!"); close(*client_socket); free(client_socket); continue; } pthread_detach(tid); } close(server_socket); return 0; }以上代码哪里有问题
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值