Я работаю над проектом, в котором реализую HTTP-сервер на C, и столкнулся с проблемой рендеринга изображений в веб-браузере. Каждый раз, когда я пытаюсь получить доступ к изображению через сервер, я получаю сообщение об ошибке «невозможно отобразить изображение, поскольку оно содержит ошибку».
Я тщательно проверил свой код, но не могу точно определить проблему. Может ли кто-нибудь подсказать мне, что я делаю неправильно? Ниже приведена упрощенная версия моего кода для обслуживания изображений:
main.c
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT "8080"
#define BUFFSIZE 2048
#define RESSIZE 4096
#include "filehandle.h"
#include "httpresponse.h"
char *get_file_path(const char *request) {
char *path = NULL;
char *start = strstr(request, "GET ");
if (start != NULL) { start += 4; // Move past "GET " char *end = strstr(start, " "); if (end != NULL) {
int path_length = end - start;
path = (char *)malloc(path_length + 1);
strncpy(path, start, path_length);
path[path_length] = '\0'; }
}
return path; };
char *requestpath(int sockfd) {
char *buffer = (char *)malloc(BUFFSIZE);
int bytes = read(sockfd, buffer, BUFFSIZE);
return buffer; };
int main(int argc, char *argv[]) {
int status;
struct addrinfo hints, *res;
int sockfd;
int bindstatus;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
status = getaddrinfo(NULL, PORT, &hints, &res);
if (status == -1) { fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
}
sockfd = socket(res->ai_family, res->ai_socktype, 0);
if (sockfd == -1) { fprintf(stderr, "socket error %s\n", strerror(sockfd));
}
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
bindstatus = bind(sockfd, res->ai_addr, res->ai_addrlen);
if (bindstatus == -1) { fprintf(stderr, "bind error %s\n", strerror(bindstatus));
}
freeaddrinfo(res);
int l;
l = listen(sockfd, 10);
if (l != 0) { fprintf(stderr, "LISTEN ERROR %s\n", strerror(l));
}
while (1) { struct sockaddr_in client_addr; int newfd; socklen_t theiraddr = sizeof client_addr; newfd = accept(sockfd, (struct sockaddr *)&client_addr, &theiraddr);
if (newfd == -1) {
fprintf(stderr, "accept error %s\n", strerror(errno)); } else {
char str[INET_ADDRSTRLEN];
inet_ntop(client_addr.sin_family, (struct inaddr *)&client_addr.sin_addr,
str, INET_ADDRSTRLEN);
printf("connection from %s\n", str); }
char *request = requestpath(newfd); char *filepath = get_file_path(request); printf("%s\n", filepath); free(request);
char *response = NULL;
if (strcmp(filepath, "/") == 0 || strcmp(filepath, "/index.html") == 0) {
response = content("index.html");
char *http_response = (char *) malloc(RESSIZE);
char *date = get_date_for_server();
int content_length = strlen(response);
int len,bytes_sent;
int n = snprintf(http_response,RESSIZE,"HTTP/1.1 200 OK\r\nAcess-Control-Allow-Origin: *\r\nConnection: Keep-Alive\r\nDate: %s\r\nContent-Type: %s\r\nContent-Length: %llu\r\n\n%s",date,"text/html",content_length,response);
len = strlen(http_response);
bytes_sent = send(newfd,http_response,len,0);
free(date);
free(http_response);
shutdown(newfd, SHUT_WR);
}
else if (strcmp(filepath,"/image.jpg") == 0){
char http_header[256];
char *date = get_date_for_server();
struct file_data *fdata = NULL;
fdata = read_file("image.jpg");
if (fdata == NULL)
fprintf(stderr,"Error opening binary file");
uint8_t buff[fdata->length];
FILE *wbf = fopen("test.jpg","wb");
fwrite(buff,fdata->length,1,wbf);
fclose(wbf);
snprintf(http_header,256,"HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nContent-Length: %llu\r\n",fdata->length);
send(newfd,http_header,strlen(http_header),0);
send(newfd,fdata->data,fdata->length,0);
printf("length is %ld\n",fdata->length);
shutdown(newfd, SHUT_WR);
fdata = NULL;
}
else
shutdown(newfd, SHUT_WR);
}
close(sockfd);
return 0; }
вот мой дескриптор файла.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define BUFFSIZE 2048
typedef struct file_data {
uint8_t *data;
size_t length;
}file_data;
struct file_data *read_file(const char *path){
FILE *handler = NULL;
struct file_data *fdata = NULL;
size_t read_length = 0;
uint8_t buffer[BUFFSIZE] = {0x00};
fdata = malloc(sizeof(struct file_data));
if (fdata == NULL)
return NULL;
bzero(fdata, sizeof(struct file_data));
fdata->data = malloc(1);
if (fdata->data == NULL){
free(fdata);
return NULL;
}
handler = fopen(path,"rb");
if (handler == NULL){
free(fdata->data);
free(fdata);
return NULL;
}
while(!feof(handler)){
read_length = fread(buffer,1,BUFFSIZE,handler);
fdata->data = realloc(fdata->data,fdata->length + read_length);
if (fdata->data == NULL){
fclose(handler);
free(fdata);
return NULL;
}
memcpy(fdata->data +fdata->length, buffer, read_length);
fdata->length += read_length;
}
fclose(handler);
return fdata;
}
// open the requested file and return the file pointer
FILE* requestfile(char *filename){
FILE *fp;
fp = fopen(filename,"r");
if (fp != NULL){
return fp;
}
else{
perror("Error opening file\n");
}
}
// count the byte size of file
int count_file_bytes(FILE *fp)
{
int c,count = 0;
if (fp != NULL){
while((c = fgetc(fp)) != EOF)
count++;
}
fclose(fp);
return count;
}
// read the file content to buffer and return
char* content(char *filename)
{
FILE *fp = requestfile(filename);
int bytecount = count_file_bytes(fp);
char *content = (char *) malloc(bytecount+1);
FILE *file = requestfile(filename);
size_t i;
for(i=0;i<(bytecount+1);++i)
{
int c = fgetc(file);
if ( c == EOF)
{
break;
}
content[i]= c;
}
content[i] = '\0';
fclose(file);
return content;
}
// get file extension before last '.'
char *get_file_ext(char *filename, int c)
{
char *type = strrchr(filename,c);
return type;
}
// read the file in binary format
char *read_binary_file(char *filename)
{
FILE *fp = fopen(filename,"rb");
if (fp == NULL)
fprintf(stderr,"\t Error Opening file: %s\n",filename);
long image_size;
int c;
int count = 0;
fseek(fp,0,SEEK_END);
image_size = ftell(fp);
rewind(fp);
char *buffer = (char *)malloc(image_size);
fread(buffer,1,image_size,fp);
fclose(fp);
return buffer;
}
В вашем коде также много утечек памяти.
Примечание: вам следует добавить дополнительный \r\n
между заголовками и содержимым. Developer.mozilla.org/en-US/docs/Web/HTTP/Messages
Спасибо, что добавили дополнительный \r\n, исправивший проблему.
Проблема заключалась в отсутствии \r\n
в заголовке и контенте.
это решило проблему
snprintf(http_header,256,"HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nContent-Length: %llu\r\n\r\n",fdata->length);
В проблеме не хватало \r\n
.
1) Почему « while( !feof(file))» всегда неверно?2) TCP — потоковый протокол, где данные — это просто поток байтов без начала и конца. Второй момент означает, что вам нужно использовать циклы как для записи, так и для чтения данных в сокеты или из них. И вам нужен какой-то способ узнать, когда и где заканчивается сообщение (например, отправка размера или использование какой-либо последовательности границ сообщения).