Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

250 lines (220 sloc) 8.175 kB
/*
Onion HTTP server library
Copyright (C) 2010 David Moreno Montero
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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <onion/mime.h>
#include "../common/updateassets.h"
void print_help();
char *funcname(const char *prefix, const char *filename);
void parse_file(const char *prefix, const char *filename, FILE *outfd, onion_assets_file *assets);
void parse_directory(const char *prefix, const char *dirname, FILE *outfd, onion_assets_file *assets);
int main(int argc, char **argv){
if (argc==1)
print_help(argv[0]);
int i;
char *outfile=NULL;
char *assetfile="assets.h";
// First pass cancel out the options, let only the files
for (i=1;i<argc;i++){
if (strcmp(argv[i],"--help")==0)
print_help();
else if (strcmp(argv[i],"-o")==0){
if (i>=argc-1){
fprintf(stderr,"ERROR: Need an argument for -o");
exit(2);
}
outfile=argv[i+1];
argv[i]=NULL; // cancel them out.
argv[i+1]=NULL;
i++;
}
else if (strcmp(argv[i],"-a")==0){
if (i>=argc-1){
fprintf(stderr,"ERROR: Need an argument for -a");
exit(2);
}
assetfile=argv[i+1];
argv[i]=NULL; // cancel them out.
argv[i+1]=NULL;
i++;
}
}
FILE *outfd=stdout;
if (outfile){
outfd=fopen(outfile,"w");
if (!outfd){
perror("ERROR: Could not open output file");
exit(2);
}
}
onion_assets_file *assets=onion_assets_file_new(assetfile);
// Some header...
fprintf(outfd,"/** File autogenerated by opack **/\n\n");
fprintf(outfd,"#include <onion/request.h>\n\n");
fprintf(outfd,"#include <onion/response.h>\n\n");
fprintf(outfd,"#include <string.h>\n\n");
for (i=1;i<argc;i++){
if (argv[i]){
struct stat st;
stat(argv[i], &st);
if (S_ISDIR(st.st_mode)){
parse_directory(basename(argv[1]), argv[i], outfd, assets);
}
else{
parse_file("", argv[i], outfd, assets);
}
}
}
if (outfile){
fclose(outfd);
}
onion_assets_file_free(assets);
return 0;
}
/// Parses a filename to a function name (changes non allowed chars to _)
char *funcname(const char *prefix, const char *filename){
int l=8;
if (prefix)
l+=strlen(prefix);
if (filename)
l+=strlen(filename);
char *ret=malloc(l);
strcpy(ret,"opack_");
if (prefix && prefix[0]!='\0')
strcat(ret, prefix);
if (prefix && prefix[0]!='\0' && filename && filename[0]!='\0')
strcat(ret, "_");
if (filename && filename[0]!='\0')
strcat(ret, filename);
int i=0;
while(ret[i]!='\0'){
if ( !((ret[i]>='a' && ret[i]<='z') || (ret[i]>='A' && ret[i]<='Z') || (ret[i]>='0' && ret[i]<='9')) )
ret[i]='_';
i++;
}
return ret;
}
/**
* @short Generates the necesary data to the output stream.
*/
void parse_file(const char *prefix, const char *filename, FILE *outfd, onion_assets_file *assets){
FILE *fd=fopen(filename, "r");
if (!fd){
fprintf(stderr,"ERROR: Cant open file %s: ",filename);
perror("");
onion_assets_file_free(assets);
exit(3);
}
char *fname=funcname(prefix, basename((char*)filename));
char buffer[4096];
buffer[4095]=0;
snprintf(buffer, sizeof(buffer)-1, "onion_connection_status %s(void *_, onion_request *req, onion_response *res);", fname);
onion_assets_file_update(assets,buffer);
fprintf(stderr, "Parsing: %s to '%s'.\n",filename, buffer);
fprintf(outfd,"onion_connection_status %s(void *_, onion_request *req, onion_response *res){\n static const char data[]={\n",fname);
int r, i, l=0;
while ( (r=fread(buffer,1,sizeof(buffer)-1,fd)) !=0 ){
for (i=0;i<r;i++){
fprintf(outfd,"0x%02X, ", buffer[i]&0x0FF);
if ((i%16) == 15){
fprintf(outfd,"\n");
}
}
l+=r;
}
fprintf(outfd,"};\n");
const char *mime_type=onion_mime_get(filename);
fprintf(outfd," onion_response_set_length(res, %d);\n", l);
fprintf(outfd," onion_response_set_header(res, \"Content-Type\", \"%s\");\n", mime_type);
fprintf(outfd," return onion_response_write(res, data, sizeof(data));\n}\n\n");
fprintf(outfd,"const unsigned int %s_length = %d;\n\n",fname,l);
fclose(fd);
free(fname);
}
/**
* @short Bulk converts all files at dirname, excepting *~, and the creates a handler for such directory.
*/
void parse_directory(const char *prefix, const char *dirname, FILE *outfd, onion_assets_file *assets){
DIR *dir=opendir(dirname);
if (!dir){
fprintf(stderr, "ERROR: Could not open directory %s, check permissions.", dirname);
exit(4);
}
// First create other files/dirs
struct dirent *de;
char fullname[1024];
while ( (de=readdir(dir)) ){
if (de->d_name[0]=='.' || de->d_name[strlen(de->d_name)-1]=='~')
continue;
snprintf(fullname, sizeof(fullname), "%s/%s", dirname, de->d_name);
if (de->d_type==DT_DIR){
char prefix2[256];
snprintf(prefix2, sizeof(prefix2), "%s/%s", prefix, de->d_name);
parse_directory(prefix2, fullname, outfd, assets);
}
else
parse_file(prefix, fullname, outfd, assets);
}
closedir(dir);
// Now create current
char *fname=funcname(prefix, NULL);
snprintf(fullname, sizeof(fullname), "onion_connection_status %s(void *_, onion_request *req, onion_response *res);", fname);
onion_assets_file_update(assets, fullname);
fprintf(stderr, "Parsing directory: %s to '%s'.\n",dirname, fullname);
fprintf(outfd,"onion_connection_status %s(void *_, onion_request *req, onion_response *res){\n", fname);
fprintf(outfd," const char *path=onion_request_get_path(req);\n\n");
dir=opendir(dirname);
while ( (de=readdir(dir)) ){
if (de->d_name[0]=='.' || de->d_name[strlen(de->d_name)-1]=='~')
continue;
char *fname=funcname(prefix, de->d_name);
if (de->d_type==DT_DIR){
int l=strlen(de->d_name);
fprintf(outfd, " if (strncmp(\"%s/\", path, %d)==0){\n", de->d_name, l+1);
fprintf(outfd, " onion_request_advance_path(req, %d);\n", l+1);
}
else
fprintf(outfd, " if (strcmp(\"%s\", path)==0){\n", de->d_name);
fprintf(outfd, " return %s(_, req, res);\n", fname);
fprintf(outfd, " }\n");
free(fname);
}
closedir(dir);
fprintf(outfd," return OCS_NOT_PROCESSED;\n");
fprintf(outfd,"}\n\n");
free(fname);
}
/// Shows the help
void print_help(const char *name){
fprintf(stderr,"%s -- Packs a given file or files into a C function that will print it out\n\n", name);
fprintf(stderr,"Usage: %s <file1> <file2> -o <outfile.c>\n", name);
fprintf(stderr," %s <dir1> <dir2> <file3> -o <outfile.c>\n\n", name);
fprintf(stderr,"Options:\n");
fprintf(stderr," --help Shows this help\n");
fprintf(stderr," -o <filename.c> Output filename\n");
fprintf(stderr," -a <filename.h> Asset header file. By default assets.h\n\n");
fprintf(stderr,"It later creates a series of functions, with the name of the file or directory, and with the following signature.\n");
fprintf(stderr," int opack_[file_name_and_extension](void *_, onion_request *request, onion_response *response);\n\n");
fprintf(stderr,"An asset header file is created/updated with the opack needed handlers.");
fprintf(stderr,"With this signature handlers are very easily used from onion.\n\n");
fprintf(stderr,"If its a directory, access is as expected using the path, but only last element: static/jquery.min.js, for example if you pack static with jquery.min.js at src/static/. It is recursive.\n");
fprintf(stderr,"In directory mode, files ending with ~ and starting with . are ignored.\n");
exit(1);
}
Jump to Line
Something went wrong with that request. Please try again.