/* * Handle creation of file to be displayed. * Arguments: * user Is owner name of poster. * text_flag If true, value argument is a text string, else value * is a URL to be fetched. * value Value string from form, either text or URL. * show_file. Used as template for creating new file. * new_file returns created file name. * content_type Returns content-type: header, text/plain if text. */ #include #include #include #include #include #ifdef VMS #include #include #include #include #else #include #include #include #include #endif #include #include #include "cgilib.h" static int copy_url(); int copy_message ( char *user, int text_flag, char *value, char *showfile, char *new_file, char *content_type ) { int length, status; char *res; FILE *mf; /* * make new file. */ strcpy ( new_file, showfile ); length = strlen ( showfile ); strcpy ( &new_file[length], "-XXXXXX" ); res = mktemp ( new_file ); mf = fopen ( new_file, "w" ); if ( !mf ) return 0; if ( text_flag ) { /* * Write contents to message file. */ length = fwrite ( value, strlen(value), 1, mf ); length = fwrite ( "\n", 1, 1, mf ); strcpy ( content_type, "text/plain" ); } else { status = copy_url ( user, value, mf, content_type ); } fclose ( mf ); return 1; } /* * See if header line matches input. */ static void update_field ( char *hdr, char *field_name, char *value ) { int i, j, k, len; char *line; /* * Match header, return if no match. */ for ( i = j = 0; hdr[j]; j++ ) if ( hdr[j] == '\n' ) { line = &hdr[i]; i = j + 1; for ( k = 0; line[k] != ':'; k++ ) { if ( line[k] == '\n' ) break; if ( _tolower(line[k]) != field_name[k] ) break; if ( !field_name[k] ) break; } if ( line[k] == ':' && field_name[k] == '\0' ) { /* trim leading spaces */ for ( k++; (line[k] != '\n') && isspace(line[k]); k++ ); line = &line[k]; for ( len=0; line[len] != '\n'; len++ ); /* Trim trailing spaces */ while ( len > 0 ) { len--; if ( !isspace(line[len]) ) break; } if ( len > 254 ) len = 254; strncpy ( value, line, len+1 ); value[len+1] = '\0'; printf("Extracted %s: '%s'\n", field_name, value ); return; } } } static int copy_url ( char *user, char *url, FILE *mf, char *content_type ) { int status, sd, i, j, timeout, in_hdr, rem_port, http_parse_url(); int binary_mode, simple_request; struct sockaddr local, remote; struct hostent *hostinfo; char *arg_url, *service, *node, *ident, *arg, *remote_host; char url_buf[1024]; /* * Extract arguments from command line. */ arg_url = url; binary_mode = 1; simple_request = 0; /* * Parse target. */ status = http_parse_url ( url, url_buf, &service, &remote_host, &ident, &arg ); rem_port = 80; for ( j = 0; remote_host[j]; j++ ) if ( remote_host[j] == ':' ) { rem_port = atoi ( &remote_host[j+1] ); remote_host[j] = '\0'; break; } if ( !*remote_host ) { char *def_port; remote_host = cgi_info ( "SERVER_NAME" ); if ( !remote_host ) remote_host = "localhost"; def_port = cgi_info ( "SERVER_PORT" ); if ( def_port ) rem_port = atoi(def_port); } else remote_host = &remote_host[1]; /* * Create socket on first available port. */ sd = socket ( AF_INET, SOCK_STREAM, 0 ); if ( sd < 0 ) { fprintf(stderr,"Error creating socket: %s\n", strerror(errno) ); } local.sa_family = AF_INET; for ( j = 0; j < sizeof(local.sa_data); j++ ) local.sa_data[j] = '\0'; status = bind ( sd, &local, sizeof ( local ) ); if ( status < 0 ) { fprintf(stderr,"Error binding socket: %s\n", strerror(errno) ); } /* * Lookup host. */ hostinfo = gethostbyname ( remote_host ); if ( !hostinfo ) { fprintf(stderr, "Could not find host '%s'\n", remote_host ); return EXIT_FAILURE; } remote.sa_family = hostinfo->h_addrtype; for ( j = 0; j < hostinfo->h_length; j++ ) { remote.sa_data[j+2] = hostinfo->h_addr_list[0][j]; } remote.sa_data[0] = rem_port >> 8; remote.sa_data[1] = (rem_port&255); /* * Connect to remote host. */ status = connect ( sd, &remote, sizeof(remote) ); if ( status == 0 ) { int length; char response[1024]; /* * Send request followed by newline. */ in_hdr = !simple_request; if ( in_hdr ) sprintf(response, "GET %s%s HTTP/1.0\r\n\r\n", ident, arg ); else sprintf(response, "GET %s%s\r\n", ident, arg ); status = send ( sd, response, strlen(response), 0 ); if ( status < 0 ) fprintf(stderr,"status of write: %d %d\n", status, errno ); strcpy ( content_type, "Text/plain" ); /* * Read and echo response. */ if ( status > 0 ) { int i, j, cr, hdr_state; char ch; FILE *outf, *cur_outf; cr = 0; outf = mf; cur_outf = (in_hdr) ? stdout : outf; hdr_state = 0; while (0 < (length=recv(sd, response, sizeof(response)-1,0))) { if ( binary_mode && !in_hdr ) { fwrite ( response, 1, length, cur_outf ); } else { for ( i = j = 0; i < length; i++ ) { ch = response[i]; if ( response[i] == '\r' ) { if ( cr == 1 ) response[j++] = '\r'; cr = 1; } else if ( cr == 1 ) { if ( ch != '\n' ) response[j++] = '\r'; response[j++] = ch; cr = 0; } else { response[j++] = ch; cr = 0; } if ( in_hdr && (ch == '\n') && !cr ) { if ( hdr_state ) { in_hdr = 0; response[j] = '\0'; update_field ( response, "content-type", content_type ); if ( j > 0 ) fprintf (cur_outf,"%s",response); cur_outf = outf; if ( binary_mode ) { i++; if ( i < length ) fwrite (&response[i], 1, length-i,outf); break; } j = 0; } hdr_state = 1; } else if ( !cr ) hdr_state = 0; } response[j] = '\0'; if ( !binary_mode ) fwrite(response, j, 1, cur_outf ); } } if ( outf != stdout ) fprintf(outf,"\n"); if (outf != stdout) fclose(outf); } } else { fprintf(stderr, "error connecting to '%s': %d/%d\n", remote_host, status, errno ); } close ( sd ); return EXIT_SUCCESS; } /***************************************************************************/ int http_parse_url ( char *url, /* locator to parse */ char *info, /* Scratch area for result pts*/ char **service, /* Protocol (e.g. http) indicator */ char **node, /* Node name. */ char **ident, /* File specification. */ char **arg ) /* Search argument */ { int i, state; char *last_slash, *p, c, arg_c; /* * Copy contents of url into info area. */ *service = *node = *ident = *arg = last_slash = ""; for ( state = i = 0; (info[i] = url[i]) != 0; ) { c = info[i]; switch ( state ) { case 0: if ( c == ':' ) { info[i] = '\0'; /* terminate string */ *service = info; state = 1; } case 1: if ( c == '/' ) { *ident = last_slash = &info[i]; state = 2; } break; case 2: state = 4; if ( c == '/' ) { /* 2 slashes in a row */ *node = *ident; state = 3; } else if ( (c == '#') || (c == '?') ) { arg_c = c; info[i] = '\0'; *arg = &info[i+1]; state = 5; } break; case 3: /* find end of host spec */ if ( c == '/' ) { state = 4; *ident = last_slash = &info[i]; for ( p = *node; p < *ident; p++ ) p[0] = p[1]; info[i-1] = '\0'; /* Terminate host string */ } break; case 4: /* Find end of filename */ if ( c == '/' ) last_slash = &info[i]; else if ( (c == '#') || (c == '?') ) { arg_c = c; info[i] = '\0'; *arg = &info[i+1]; state = 5; } case 5: break; } i++; } /* * Insert arg delimiter back into string. */ if ( **arg ) { char tmp; for ( p = (*arg); arg_c; p++ ) { tmp = *p; *p = arg_c; arg_c = tmp; } *p = '\0'; } return 1; }