Gzip string unable to concatenate to a string - html

I'm a newbie in c++ and I've been trying to search for an answer to this question but can hardly found an answer I'm trying to compress an html string body with zlib in gzip compression the compression gets done successfully but when I try to concatenate it to another string it won't concatenate at all rendering the body to be blank here is the compression code:
void compress_message(){
z_stream zs;
char outbuffer[32768];
long strlen = content.size();
int ret;
string outstring;
memset(&zs, 0, sizeof(zs));
if (deflateInit2(&zs,
Z_BEST_COMPRESSION,
Z_DEFLATED,
MOD_GZIP_ZLIB_WINDOWSIZE + 16,
MOD_GZIP_ZLIB_CFACTOR,
Z_DEFAULT_STRATEGY) != Z_OK
) {
throw(std::runtime_error("deflateInit2 failed while compressing."));
}
content = "";
zs.next_in = (Bytef*) content.data();
zs.avail_in = strlen;
do {
//cout << "compressing..." << endl;
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = deflate(&zs, Z_FINISH);
if (content.size() < zs.total_out) {
// append the block to the output string
content.append(outbuffer,
zs.total_out - content.size());
}
} while (ret == Z_OK);
deflateEnd(&zs);
//cout << "original: " << content << endl;
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
ostringstream oss;
oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
throw(std::runtime_error(oss.str()));
}
}
base64 conversion function:
string tobase64(string data) {
string code64,
output = "";
int i = 0,
j = 0;
unsigned int slen = data.size();
const char* bytes_to_encode;
code64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
unsigned char char_array_3[3],
char_array_4[4];
bytes_to_encode = data.c_str();
while(slen--){
char_array_3[i++] = bytes_to_encode[j++];
if(3 == i){
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; i < 4; i++){
output += code64[char_array_4[i]];
}
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
for (j = 0; (j < i + 1); j++)
output += code64[char_array_4[j]];
while((i++ < 3))
output += '=';
}
return output;
}
the string is successfully compressed but when I concatenate it to the string response like:
string final_content = ("HTTP/1.1 200 OK\r\n"+headers+"\r\n\r\n");
content = tobase64(content);
final_content += content;
I also tried
final_content.append(content);
They both have the same result the body is never concatenated the final_content when printed only shows:
HTTP/1.1 200 OK
...
Content-type: text/html
and the compressed string is never included have been trying to find answers online and couldn't figure it out please help. I'm working this on ubuntu 18.04

Related

Refer to json individual objects in cpp crow

i am using a cpp crow library and i am having difficulty in accessing individual objects i am attaching my code here.
CROW_ROUTE(app,"/hello/<string>")
([](string name){
crow::json::wvalue x;
x["name"] = "llllds";
x["Town"] = "Texas";
x["nickname"] = "drax";
x["father"] = "Nethan";
if (name == "Nothing")
cout << "Bad Responce";
std::ostringstream os;
cout << name << " is the required query";
val = x[name];
return val;
And i want to return my name can anyone help me with this. Thanks in advance
I used JSON for Modern C++ within crow (https://github.com/nlohmann/json)
Here is an example CROW_ROUTE I wrote
CROW_ROUTE(app, "/palindromes/<string>/<string>")([](const request &req, response &res, string ID, string words){
palindromeHash.insert({ID, words}); //ignore this
nlohmann::json x;
x = getPalindromes(palindromeHash.at(ID));
palindromeHash.erase(ID); //ignore this
res.sendJSON(x);
});
//getPalindromesFunction()
nlohmann::json getPalindromes(string data){
nlohmann::json x;
unordered_map<string, bool> hashmap;
string word = "";
std::string::size_type i = data.find("%20");
while (i != std::string::npos){
data.erase(i, 3);
data.insert(i, " ");
i = data.find("%20", i);
}
for(int i = 0; i < data.size(); i++){
if(data[i] == ' '){
hashmap.insert({word, true});
word = "";
}
else{
word += data[i];
}
}
string temp;
vector<string> words;
int numValid = 0;
for(auto& i: hashmap){
temp = i.first;
reverse(temp.begin(), temp.end());
auto got = hashmap.find(temp);
if(got != hashmap.end()){
words.push_back(i.first);
numValid++;
}
}
x["words"] = words;
x["numValid"] = numValid;
return x;
}
As you can see it returns a JSON object x that holds palindromes. The sendJSON() function is something I added to crow_all.h. Add it under the struct response section on line 7215
void sendJSON(const nlohmann::json& data){
std::string response = data.dump();
add_header("Access-Control-Allow-Origin", "*");
add_header("Content-Type", "text/html");
write(response);
end();
}
Remember to include "json.h" in both main.cpp and crow_all.h. The res.sendJSON will send it to my JS file which can loop through the JSON with ease.
$.get("/palindromes/" + ID + "/" + curr_line, {}, function(response){
let x = JSON.parse(response); //This will allow JS to read the C++ JSON
for(let i = 0; i < x.words.length; i++){
term.write(x.words[i] + "\r\n");
}
}

simple HTML validator

I have a homework problem which asks me to write a simple HTML validator which checks for matching start and end tags.
Here is my code and input file below.
void removeSpaces(std::string &str){
int count = 0;
for (int i = 0; str[i]; i++)
if (str[i] != ' ')
str[count++] = str[i];
str[count] = '\0';
}
bool isHtmlMatched(std::vector<std::string>& htmlTags){
std::stack<std::string> temp;
typedef std::vector<std::string>::const_iterator Iter;
for (int i = 0; i < htmlTags.size(); i++){
if (htmlTags[i][1] != '/')
temp.push(htmlTags[i]);
else{
if (temp.empty()) return false;
std::string open = temp.top().substr(1);
std::string close = htmlTags[i].substr(2);
std::cout << open << " " << close <<std::endl;
if (open != close){
std::cout << "Failed at where " << temp.top() << " didnt match with " << htmlTags[i] << std::endl;
return false;
}
else{
temp.pop();
}
}
}
if(temp.empty()){
return true;
}
else{
std::cout << " These start tags ";
while(!temp.empty()){
std::cout << temp.top() << " ";
temp.pop();
}
std::cout << "do not have a matching end tag " <<std::endl;
return false;
}
}
int main() {
std::vector<std::string> htmlTags;
std::string input_line;
std::ifstream file("Validhtml.txt");
std::string tag;
int line = 0;
while(std::getline(file, input_line)){
int pointer = 0;
int position_start = input_line.find("<",pointer);
while (position_start != std::string::npos){
if(input_line.find(">", position_start + 1) == std::string::npos){
std::cout << "INVALID HTML" << std::endl;
std::cout << "ERROR ON LINE " << line + 1 << std::endl;
return 0;
}
int position_end = input_line.find(">", position_start + 1);
tag = input_line.substr(position_start, position_end - position_start + 1);
removeSpaces(tag);
htmlTags.push_back(tag);
pointer = position_end + 1;
position_start = input_line.find("<", pointer);
}
line++;
}
for(int i = 0; i < htmlTags.size(); i++){
std::cout << htmlTags[i] << std::endl;
}
if(!isHtmlMatched(htmlTags)){
std::cout << "INVALID HTML" << std::endl;
}
else{
std::cout << "VALID HTML" << std::endl;
}
return 0;
}
Input file:
<html><
head></head><body> My HTML page
<p></p> <h2>Hello world! </ h2>
<ol><li> #myfiles</li>
</ol>
</body >
</html>
I currently have two problem with this code.
I don't know how to read tags that are split in different lines, for example the <head> tag at the end of the first and start of the second line of the input file.
Even after I removed all the white space, this program still won't recognize <h2> and </ h2> are a matching tag. Same issue goes for <body> and </body >
Hope someone can help me with this.
I worked on this for a bit and got something I think should work for you.
Here's how the code works: First, we open the html file and push it all into a string with no whitespace. Next, we send that string to a function to detect tags. Once a tag is detected, we try to see if its an opening or closing tag. We then save the tag to the correct container (either the opening_tags container or the closing_tags container). Finally, we run a series of tests on the two containers we have. (1) Are they the same size? (2) Are they empty (meaning no tags were detected)? (3) Do all tags in the opening_tags container correspond to a tag in the closing_tags container.
If all three of our tests are passed, then we can say the html file is valid (based on tag matching).
For the containers, I used hashsets (known as std::unordered_set in C++). This is because hashsets are really fast in inserting and removing elements. In your specific instance, the order of the tags shouldn't matter. However, keep in mind that, in an actual validator, it would matter greatly.
If you have any more questions on my code, feel free to ask! Without any more waiting, here's the code:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
// Gets rid of all file white space and returns the string
std::string condense(std::ifstream&);
// Tests if all tags are matching and returns if they are
// (true) or if they aren't (false)
bool validate(const std::string&);
int main()
{
std::ifstream html_stream("input.html");
const std::string html_string = condense(html_stream);
const bool html_valid = validate(html_string);
// Prints the html string (mostly for debugging)
std::cout << html_string << '\n' << std::endl;
if (html_valid)
std::cout << "Valid HTML!" << std::endl;
else
std::cout << "Invalid HTML..." << std::endl;
}
std::string condense(std::ifstream& stream)
{
std::string file_no_whitespace;
if (stream.is_open())
{
std::string cur_token;
while (stream >> cur_token)
file_no_whitespace += cur_token;
}
else
std::cerr << "File is not open!" << std::endl;
return file_no_whitespace;
}
bool validate(const std::string& data)
{
// These should be the same size if the html is valid
// (based only on tag matching)
std::unordered_set<std::string> opening_tags, closing_tags;
// For tags like '<br />'
std::unordered_set<std::string> self_closing_tags;
// Keeps track of the current tag to push into either
// opening_tags or closing_tags
bool tagging_open;
// Process each character to make tags
for (size_t i = 0; i < data.size(); ++i)
{
const auto* cur_char = &data.at(i);
if (*cur_char == '<')
{
std::string cur_tag;
if (*(cur_char + 1) == '/')
{ // Test for closing tag
tagging_open = false;
i++;
cur_char++;
}
else // Tag is an opening tag
tagging_open = true;
i++;
cur_char++;
while (*cur_char != '>') // Until tag closes
{
cur_tag += *cur_char;
i++;
cur_char++;
}
// Test for self-closing tag
if (*(cur_char - 1) == '/')
self_closing_tags.insert(cur_tag);
// Not self-closing, so it's a normal type of tag
else if (tagging_open)
opening_tags.insert(cur_tag);
else if (!tagging_open)
closing_tags.insert(cur_tag);
}
}
// If the hashsets aren't the same size, then we automatically know
// there is at least one unmatched tag
if (opening_tags.size() != closing_tags.size())
return false;
// If the hashsets are both empty, then we know there are no tags
if (opening_tags.empty())
return false;
// If both above tests have been passed, we now need to make sure that
// every opening tag has a matching closing tag
std::vector<bool> tag_match(opening_tags.size(), false);
size_t tag_match_pos = 0;
for (const auto& tag : opening_tags)
{
auto closing_tag_itr = closing_tags.find(tag);
if (closing_tag_itr != std::end(closing_tags))
{
tag_match.at(tag_match_pos) = true;
tag_match_pos++;
// Remove match tag to avoid duplicates causing false-positives
closing_tags.erase(closing_tag_itr);
}
}
bool all_matched = true;
for (const auto& match : tag_match)
{ // Make sure all values in the 'tag_match' vector are true
if (!match)
{
all_matched = false;
break;
}
}
return all_matched;
}

In the Arduino IDE, why does the second call of a function change the previous call results?

I tried to write a function that converts a string of hex values into a string of Unicode UTF-8 characters. When this function is called once, everything is fine. But when the function is called twice in succession with the same or different arguments, both output strings are meaningless.
void HEX2String(String* HEXstr, String* str) {
String s2 = "", s3 = "";
long c, c1, c0;
char ch[2] = { 0 };
for (int i = 0; i <= HEXstr->length() - 4; i = i + 4) {
s2 = HEXstr->substring(i, i + 1) + "x" + HEXstr->substring(i + 1, i + 4);
c = (hex2long(&s2));
if (c < 255)
*str += String((char)c);
else {
c1 = (128 + (c & B111111));
c0 = (192 + (c >> 6));
ch[1] = c1;
ch[0] = c0;
str->concat(ch);
}
}
}
String str1 = "0628064700200646062706450020062E062F0627000A0633064406270645000A064806310648062F0020062806470020063306CC0633062A06450020062A064806330637";
String str = "0628064700200646062706450020062E062F0627000A0633064406270645000A064806310648062F0020062806470020063306CC0633062A06450020062A064806330637000A00730061006C0061006D0020006200610072002000730068006F006D0061";
String msg = "";
void setup() {
Serial.begin(9600);
//First call
HEX2String(&str, &msg);
Serial.println(msg);
msg = "";
//Second call
HEX2String(&str1, &msg);
Serial.println(msg);
}
void main() {
//
}
If I comment the second call, the output in the serial monitor is:
سلام
ورود به سیستم توسط
salam bar shoma
It is correct. If the second call is not commented, the output in the serial monitor is:
ب⸮⸮ه⸮⸮ ن⸮⸮ا⸮⸮م⸮⸮ خ⸮⸮د⸮⸮ا⸮⸮
س⸮⸮ل⸮⸮ا⸮⸮م⸮⸮
و⸮⸮ر⸮⸮و⸮⸮د⸮⸮ ب⸮⸮ه⸮⸮ س⸮⸮ی⸮⸮س⸮⸮ت⸮⸮م⸮⸮ ت⸮⸮و⸮⸮س⸮⸮ط⸮⸮
salam bar shomaب⸮⸮ه⸮⸮ ن⸮⸮ا⸮⸮م⸮⸮ خ⸮⸮د⸮⸮ا⸮⸮
س⸮⸮ل⸮⸮ا⸮⸮م⸮⸮
و⸮⸮ر⸮⸮و⸮⸮د⸮⸮ ب⸮⸮ه⸮⸮ س⸮⸮ی⸮⸮س⸮⸮ت⸮⸮م⸮⸮ ت⸮⸮و⸮⸮س⸮⸮ط⸮⸮
C-strings need to be null terminated. Your ch is not.
Define it as 3 characters:
char ch[3] = { 0 };
and add a null terminator:
ch[0] = c0;
ch[1] = c1;
ch[2] = 0;

table margin in qprint and QTextDocument using html as input

im trying to print an invoice in a4 format using qprint and QTextDocument with html ..but i couldn't find any solution to adjust the margin-left and margin-right of the html table...
my example
QString data;
m_printer.setPageSize(QPrinter::A4);
m_printer.setOrientation(QPrinter::Landscape);
QTextStream out(&m_strStream);
const int rowCount = m_TableWidget->model()->rowCount();
const int columnCount = m_TableWidget->model()->columnCount();
out << "<html>\n"
"<head>\n"
"<meta Content=\"Text/html; charset=Windows-1251\">\n"
<< QString("<title>%1</title>\n").arg("title")
<< "</head>\n"
"<body bgcolor=#ffffff link=#5000A0>\n"
"<table border=1 cellspacing=0 cellpadding=2>\n";
out << "<thead><tr bgcolor=#f0f0f0>";
for (int column = 0; column < columnCount; column++)
if (!m_TableWidget->isColumnHidden(column))
out << QString("<th>%1</th>").arg(m_TableWidget->model()->headerData(column, Qt::Horizontal).toString());
out << "</tr></thead>\n";
// data table
out << "<tr>";
for (int column = 0; column < columnCount; column++) {
if(column%7 == 1) {
QString data = m_TableWidget->model()->data(m_TableWidget->model()->index(0, column)).toString().simplified();
out << QString("<td colspan=7>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
} else if(column == 0){
QString data = m_TableWidget->model()->data(m_TableWidget->model()->index(0, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
for (int row = 1; row < rowCount; row++) {
out << "<tr>";
for (int column = 0; column < columnCount; column++) {
if(row==1 && column==1)
{ data =m_ComboBox->currentText().simplified();
}
if (!m_TableWidget->isColumnHidden(column)) {
data = m_TableWidget->model()->data(m_TableWidget->model()->index(row, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
}
out << "</table>\n"
"</body>\n"
"</html>\n";
m_document = new QTextDocument();
m_document->setHtml(m_strStream);
m_dialog = new QPrintDialog(&m_printer, NULL);
if (m_dialog->exec() == QDialog::Accepted) {
m_document->print(&m_printer);
}
delete m_document;

Sending html file with HTTP protocol over tcp and browser shows error

I'm am writing a HTTP web server when I send a text file with the equivalent content of the HTML file to the browser the browser shows it correctly but when I send the HTML file itself browser shows the HTML page for a second and then the "the connection was reset" error shows up.
I have noticed that the text file is bigger than the HTML file but I have no Idea why
text size = 286 byte
HTML size = 142 byte
and this is the HTML code:
<!DOCTYPE html>
<html>
<body>
<p>This is a paragraph.</p>
<p>This is a paragraph.</p>
<p>This is a paragraph.</p>
</body>
</html>
this is my code:
char sendBuffer[500];
FILE *sendFile = fopen("foo.html", "r");
fseek(sendFile, 0L, SEEK_END);
int sz = ftell(sendFile);
fseek(sendFile, 0L, SEEK_SET);
string s1;
s1="HTTP/1.1 200 OK\nContent-length: " + to_string(sz) + "\n";
std::vector<char> writable(s1.begin(), s1.end());
writable.push_back('\0');
strcpy(sendBuffer,(const char *)&writable[0]);
int c=send(connected,(const char*)&sendBuffer,strlen(&writable[0]),0);
printf("\nSent : %s\n",sendBuffer);
strcpy(sendBuffer,"Content-Type: text/html\n\n");
c=send(connected,(const char*)&sendBuffer,strlen("Content-Type: text/html\n\n"),0);
printf("\nSent : %s\n",sendBuffer);
char send_buffer[300];
while( !feof(sendFile) )
{
int numread = fread(send_buffer, sizeof(unsigned char), 300, sendFile);
if( numread < 1 ) break; // EOF or error
char *send_buffer_ptr = send_buffer;
do {
int numsent = send(connected, send_buffer_ptr, numread, 0);
if( numsent < 1 ) // 0 if disconnected, otherwise error
{
if( numsent < 0 ) {
if( WSAGetLastError() == WSAEWOULDBLOCK )
{
fd_set wfd;
FD_ZERO(&wfd);
FD_SET(connected, &wfd);
timeval tm;
tm.tv_sec = 10;
tm.tv_usec = 0;
if( select(0, NULL, &wfd, NULL, &tm) > 0 )
continue;
}
}
break; // timeout or error
}
send_buffer_ptr += numsent;
numread -= numsent;
}
while( numread > 0 );
}
Here is the other part of code that is used just before the code above:
int sock, connected, bytes_recieved , _true = 1 , portNumber;
char send_data [1024] , recv_data[1024];
struct sockaddr_in server_addr,client_addr;
int sin_size;
time_t t = time(NULL);
struct tm tm = *localtime(&t);
char date[50];
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Unable to create the Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(const char*)&_true,sizeof(int)) == -1) {
perror("Unable to Setsockopt");
exit(1);
}
char *server_address="127.1.1.1";
portNumber=8080;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNumber);
server_addr.sin_addr.s_addr = inet_addr("127.1.1.1");//inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr);//INADDR_ANY;
string host=server_address+':'+to_string(portNumber);
memset(&(server_addr.sin_zero),0,8);//sockaddr_in zero padding is needed
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))==-1) //bind the socket to a local address
{
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1) //listen to the socket with the specified waiting queue size
{
perror(" Listen");
exit(1);
}
cout << "MyHTTPServer waiting on port 8080" << endl;
fflush(stdout);
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
cout<< "I got a connection from (" << inet_ntoa(client_addr.sin_addr) << "," << ntohs(client_addr.sin_port) << ')' << endl;
You have two important problems I can see
Your are passing send paremeters wrong, this line (very important)
int c=send(connected,(const char*)&sendBuffer,strlen(&writable[0]),0);
should be
int c=send(connected,(const char*) sendBuffer,strlen(&writable[0]),0);
/* ^
* No ampersand
*/
since the sendBuffer array decays to a pointer and you don't need that.
You are passing the first parameter of select wrong too from the manual
nfds is the highest-numbered file descriptor in any of the three sets, plus 1
so in your case it should be
if (select(connected + 1, NULL, &wfd, NULL, &tm) > 0)
and you are using it after you call send you must call it before to see if it is possible to write to the file descriptor.
Your code is a little bit too complicated for the task it's designed to so I propose the following solution with the mentions problems fixed and some other ones improved
string text;
stringstream stream;
FILE *sendFile = fopen("foo.html", "r");
if (sendFile == NULL) /* check it the file was opened */
return;
fseek(sendFile, 0L, SEEK_END);
/* you can use a stringstream, it's cleaner */
stream << "HTTP/1.1 200 OK\nContent-length: " << ftell(sendFile) << "\n";
fseek(sendFile, 0L, SEEK_SET);
text = stream.str();
/* you don't need a vector and strcpy to a char array, just call the .c_str() member
* of the string class and the .length() member for it's length
*/
send(connected, text.c_str(), text.length(), 0);
std::cout << "Sent : " << text << std::endl;
text = "Content-Type: text/html\n\n";
send(connected, text.c_str(), text.length(), 0);
std::cout << "Sent : %s" << text << std::endl;
while (feof(sendFile) == 0)
{
int numread;
char sendBuffer[500];
numread = fread(sendBuffer, sizeof(unsigned char), 300, sendFile);
if (numread > 0)
{
char *sendBuffer_ptr;
sendBuffer_ptr = sendBuffer;
do {
fd_set wfd;
timeval tm;
FD_ZERO(&wfd);
FD_SET(connected, &wfd);
tm.tv_sec = 10;
tm.tv_usec = 0;
/* first call select, and if the descriptor is writeable, call send */
if (select(1 + connected, NULL, &wfd, NULL, &tm) > 0)
{
int numsent;
numsent = send(connected, sendBuffer_ptr, numread, 0);
if (numsent == -1)
return;
sendBuffer_ptr += numsent;
numread -= numsent;
}
} while (numread > 0);
}
}
/* don't forget to close the file. */
fclose(sendFile);
A half way answer. First off, even if “Using \n works” it is breaching the standard. One should use CRLF. Use CRLF. Period.
For the rest of the code. I doubt this is going to change many things, but I would have re-structured the code a bit. It is to much going on in the send function.
Have separated out the sending of data to own function. You could also consider even separating out send header to it's own function – if you find a good way to structure it. When you expand to send text or html or etc. and so on and so forth, you definitively should separate out header to own function. Doing it at an early stage would be helpful.
Only meant as a crude start.
int send_data(int soc, const char *buf, size_t len)
{
ssize_t sent;
do {
/* Use iharob code or similar here */
/* Return something <> 0 on error. */
sent = send(soc, buf, len, 0);
buf += sent;
len -= sent;
} while (len > 0);
return 0;
}
int send_file(int soc, const char *fn)
{
char buf[500];
FILE *fh;
long sz;
size_t len;
int err = 0;
if (!(fh = fopen(fn, "r"))) {
perror("fopen");
return 1;
}
fseek(fh, 0L, SEEK_END);
sz = ftell(fh);
fseek(fh, 0L, SEEK_SET);
/* Consider adding Date + Server here. */
len = sprintf(buf,
"HTTP/1.1 200 OK\r\n"
"Content-length: %ld\r\n"
"Content-Type: text/html\r\n"
"Server: FooBar/0.0.1\r\n"
"\r\n", sz
);
if (len < 0) {
err = 3;
fprintf(stderr, "Error writing header.\n");
goto fine;
}
/* Debug print. */
fprintf(stderr, "Header[%d]:\n'%s'\n", len, buf);
if ((err = send_data(soc, buf, len)) != 0) {
fprintf(stderr, "Error sending header.\n");
goto fine;
}
while (!feof(fh)) {
len = fread(buf, sizeof(char), 500, fh);
if (len < 1)
break;
if ((err = send_data(soc, buf, len))) {
fprintf(stderr, "Error sending file.\n");
goto fine;
}
}
if ((err = ferror(fh))) {
fprintf(stderr, "Error reading file.\n");
perror("fread");
}
fine:
fclose(fh);
return err;
}