diff options
-rw-r--r-- | amiga/bitmap.c | 15 | ||||
-rw-r--r-- | amiga/gui.c | 145 | ||||
-rw-r--r-- | amiga/theme.c | 2 | ||||
-rw-r--r-- | amiga/theme.h | 2 | ||||
-rw-r--r-- | atari/ctxmenu.c | 15 | ||||
-rw-r--r-- | atari/deskmenu.c | 12 | ||||
-rw-r--r-- | atari/gui.c | 1 | ||||
-rwxr-xr-x | atari/gui.h | 9 | ||||
-rwxr-xr-x | atari/rootwin.c | 25 | ||||
-rw-r--r-- | atari/search.c | 24 | ||||
-rw-r--r-- | atari/search.h | 4 | ||||
-rw-r--r-- | atari/toolbar.c | 2 | ||||
-rw-r--r-- | beos/window.cpp | 49 | ||||
-rw-r--r-- | content/fetch.c | 36 | ||||
-rw-r--r-- | content/fetchers/about.h | 5 | ||||
-rw-r--r-- | content/fetchers/curl.c | 1012 | ||||
-rw-r--r-- | content/fetchers/curl.h | 7 | ||||
-rw-r--r-- | content/fetchers/data.h | 10 | ||||
-rw-r--r-- | content/fetchers/file.h | 10 | ||||
-rw-r--r-- | content/fetchers/resource.h | 7 | ||||
-rw-r--r-- | utils/messages.c | 40 |
21 files changed, 720 insertions, 712 deletions
diff --git a/amiga/bitmap.c b/amiga/bitmap.c index bab6746c7..c59e34278 100644 --- a/amiga/bitmap.c +++ b/amiga/bitmap.c @@ -161,7 +161,7 @@ bool bitmap_save(void *bitmap, const char *path, unsigned flags) if(!ami_download_check_overwrite(path, NULL, 0)) return false; } - if(dto = ami_datatype_object_from_bitmap(bitmap)) + if((dto = ami_datatype_object_from_bitmap(bitmap))) { err = SaveDTObjectA(dto, NULL, NULL, path, DTWM_IFF, FALSE, NULL); DisposeDTObject(dto); @@ -295,7 +295,7 @@ void ami_bitmap_argb_to_rgba(struct bitmap *bm) } #endif -#if BITMAP_DUMP +#ifdef BITMAP_DUMP void bitmap_dump(struct bitmap *bitmap) { int x,y; @@ -362,14 +362,12 @@ struct bitmap *ami_bitmap_from_datatype(char *filename) int bm_format = PBPAFMT_ARGB; #endif - if(dto = NewDTObject(filename, + if((dto = NewDTObject(filename, DTA_GroupID, GID_PICTURE, PDTA_DestMode, PMODE_V43, PDTA_PromoteMask, TRUE, - TAG_DONE)) - { + TAG_DONE))) { struct BitMapHeader *bmh; - struct RastPort rp; if(GetDTAttrs(dto, PDTA_BitMapHeader, &bmh, TAG_DONE)) { @@ -421,9 +419,8 @@ static struct BitMap *ami_bitmap_get_truecolour(struct bitmap *bitmap,int width, ri.BytesPerRow = bitmap->width * 4; ri.RGBFormat = AMI_BITMAP_FORMAT; - if(tbm = p96AllocBitMap(bitmap->width, bitmap->height, 32, 0, - friendbm, AMI_BITMAP_FORMAT)) - { + if((tbm = p96AllocBitMap(bitmap->width, bitmap->height, 32, 0, + friendbm, AMI_BITMAP_FORMAT))) { InitRastPort(&trp); trp.BitMap = tbm; p96WritePixelArray((struct RenderInfo *)&ri, 0, 0, &trp, 0, 0, diff --git a/amiga/gui.c b/amiga/gui.c index 939619be2..1b331c046 100644 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -176,7 +176,7 @@ Class *urlStringClass; BOOL locked_screen = FALSE; BOOL screen_closed = FALSE; -ULONG screen_signal = -1; +int screen_signal = -1; struct MsgPort *applibport = NULL; ULONG applibsig = 0; @@ -411,12 +411,11 @@ static void ami_open_resources(void) { /* Allocate ports/ASL and open libraries and devices */ - if(KeymapBase = OpenLibrary("keymap.library",37)) - { + if((KeymapBase = OpenLibrary("keymap.library",37))) { IKeymap = (struct KeymapIFace *)GetInterface(KeymapBase,"main",1,NULL); } - if(ApplicationBase = OpenLibrary("application.library", 53)) { + if((ApplicationBase = OpenLibrary("application.library", 53))) { IApplication = (struct ApplicationIFace *)GetInterface(ApplicationBase, "application", 2, NULL); } @@ -550,7 +549,7 @@ static nserror ami_set_options(struct nsoption_s *defaults) (nsoption_charp(accept_language)[0] == '\0') || (nsoption_bool(accept_lang_locale) == true)) { - if(tempacceptlangs = ami_locale_langs()) + if((tempacceptlangs = ami_locale_langs())) { nsoption_set_charp(accept_language, (char *)strdup(tempacceptlangs)); @@ -589,13 +588,13 @@ static nserror ami_set_options(struct nsoption_s *defaults) BPTR lock = 0; /* Search for some likely candidates */ - if(lock = Lock("FONTS:Code2000.font", ACCESS_READ)) + if((lock = Lock("FONTS:Code2000.font", ACCESS_READ))) { UnLock(lock); nsoption_set_charp(font_unicode, (char *)strdup("Code2000")); } - else if(lock = Lock("FONTS:Bitstream Cyberbit.font", ACCESS_READ)) + else if((lock = Lock("FONTS:Bitstream Cyberbit.font", ACCESS_READ))) { UnLock(lock); nsoption_set_charp(font_unicode, @@ -628,7 +627,7 @@ static void ami_amiupdate(void) UnLock(lock); - if(lock = Lock("PROGDIR:", ACCESS_READ)) + if((lock = Lock("PROGDIR:", ACCESS_READ))) { char filename[1024]; BPTR amiupdatefh; @@ -672,8 +671,6 @@ static nsurl *gui_get_resource_url(const char *path) static void gui_init(int argc, char** argv) { - BPTR lock = 0; - ami_open_resources(); /* alloc ports/asl reqs, open libraries/devices */ ami_clipboard_init(); ami_openurl_open(); @@ -723,8 +720,7 @@ static void ami_openscreen(void) { struct ScreenModeRequester *screenmodereq = NULL; - if(screenmodereq = AllocAslRequest(ASL_ScreenModeRequest,NULL)) - { + if((screenmodereq = AllocAslRequest(ASL_ScreenModeRequest,NULL))) { if(AslRequestTags(screenmodereq, ASLSM_MinDepth, 0, ASLSM_MaxDepth, 32, @@ -762,7 +758,7 @@ static void ami_openscreen(void) FreeSignal(screen_signal); screen_signal = -1; - if(scrn = LockPubScreen("NetSurf")) + if((scrn = LockPubScreen("NetSurf"))) { locked_screen = TRUE; } @@ -801,7 +797,7 @@ static void ami_gui_commandline(int *argc, char **argv) { int new_argc = 0; struct RDArgs *args; - STRPTR template = "NSOPTS/M,URL/K,FORCE/S"; + CONST_STRPTR template = "NSOPTS/M,URL/K,FORCE/S"; long rarray[] = {0,0,0}; enum { @@ -812,7 +808,7 @@ static void ami_gui_commandline(int *argc, char **argv) if(*argc == 0) return; // argc==0 is started from wb - if(args = ReadArgs(template, rarray, NULL)) { + if((args = ReadArgs(template, rarray, NULL))) { if(rarray[A_URL]) { LOG(("URL %s specified on command line", rarray[A_URL])); temp_homepage_url = ami_to_utf8_easy((char *)rarray[A_URL]); @@ -866,7 +862,7 @@ static void gui_init2(int argc, char** argv) /* ...and this ensures the treeview at least gets the WB colour palette to work with */ if(scrn == NULL) { - if(screen = LockPubScreen("Workbench")) { + if((screen = LockPubScreen("Workbench"))) { ami_set_screen_defaults(screen); UnlockPubScreen(NULL, screen); } @@ -1059,7 +1055,7 @@ void ami_gui_history(struct gui_window_2 *gwin, bool back) int ami_key_to_nskey(ULONG keycode, struct InputEvent *ie) { int nskey = 0, chars; - UBYTE buffer[20]; + char buffer[20]; char *utf8 = NULL; if(keycode >= IECODE_UP_PREFIX) return 0; @@ -1360,7 +1356,7 @@ static void ami_gui_menu_update_all(void) { ami_menu_update_checked(gwin); } - } while(node = nnode); + } while((node = nnode)); } /** @@ -1370,8 +1366,8 @@ static void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon) { struct BitMap *bm = NULL; struct IBox *bbox; - ULONG cur_tab = 0; - struct bitmap *icon_bitmap; + int cur_tab = 0; + struct bitmap *icon_bitmap = NULL; if(nsoption_bool(kiosk_mode) == true) return; if(!g) return; @@ -1434,8 +1430,8 @@ static void ami_gui_refresh_favicon(void *p) static void ami_handle_msg(void) { - ULONG class,result,storage = 0,x,y,xs,ys,width=800,height=600; - uint16 code,quals; + ULONG result,storage = 0,x,y,xs,ys,width=800,height=600; + uint16 code; struct IBox *bbox; struct nsObject *node; struct nsObject *nnode; @@ -1645,7 +1641,7 @@ static void ami_handle_msg(void) case SELECTUP: if(gwin->mouse_state & BROWSER_MOUSE_PRESS_1) { - CurrentTime(&curtime.tv_sec, &curtime.tv_usec); + CurrentTime((ULONG *)&curtime.tv_sec, (ULONG *)&curtime.tv_usec); gwin->mouse_state = BROWSER_MOUSE_CLICK_1; @@ -1687,7 +1683,7 @@ static void ami_handle_msg(void) case MIDDLEUP: if(gwin->mouse_state & BROWSER_MOUSE_PRESS_2) { - CurrentTime(&curtime.tv_sec, &curtime.tv_usec); + CurrentTime((ULONG *)&curtime.tv_sec, (ULONG *)&curtime.tv_usec); gwin->mouse_state = BROWSER_MOUSE_CLICK_2; @@ -2141,7 +2137,7 @@ static void ami_handle_msg(void) GetClickTabNodeAttrs(tab, TNA_UserData, &bw, TAG_DONE); - } while(tab=ntab); + } while((tab=ntab)); } ami_schedule(0, ami_gui_refresh_favicon, gwin); @@ -2214,7 +2210,7 @@ static void ami_handle_msg(void) // ReplyMsg((struct Message *)message); } - } while(node = nnode); + } while((node = nnode)); if(ami_menu_window_close) { @@ -2251,7 +2247,7 @@ static void ami_handle_appmsg(void) STRPTR filename; int i = 0; - while(appmsg=(struct AppMessage *)GetMsg(appport)) + while((appmsg = (struct AppMessage *)GetMsg(appport))) { gwin = (struct gui_window_2 *)appmsg->am_UserData; @@ -2265,9 +2261,9 @@ static void ami_handle_appmsg(void) { for(i = 0; i < appmsg->am_NumArgs; ++i) { - if(appwinargs = &appmsg->am_ArgList[i]) + if((appwinargs = &appmsg->am_ArgList[i])) { - if(filename = AllocVecTagList(1024, NULL)) + if((filename = AllocVecTagList(1024, NULL))) { if(appwinargs->wa_Lock) { @@ -2498,7 +2494,7 @@ void ami_get_msg(void) } if(signal & schedulesig) { - if(timermsg = (struct TimerRequest *)GetMsg(msgport)) { + if((timermsg = (struct TimerRequest *)GetMsg(msgport))) { ReplyMsg((struct Message *)timermsg); schedule_run(FALSE); } @@ -2697,7 +2693,7 @@ void ami_quit_netsurf(void) ami_download_window_abort((struct gui_download_window *)gwin); break; } - } while(node = nnode); + } while((node = nnode)); win_destroyed = true; } @@ -2843,11 +2839,11 @@ char *ami_gui_get_cache_favicon_name(nsurl *url, bool only_if_avail) STRPTR filename = NULL; BPTR lock = 0; - if (filename = ASPrintf("%s/%x", current_user_faviconcache, nsurl_hash(url))) { + if ((filename = ASPrintf("%s/%x", current_user_faviconcache, nsurl_hash(url)))) { LOG(("favicon cache location: %s", filename)); if (only_if_avail == true) { - if(lock = Lock(filename, ACCESS_READ)) { + if((lock = Lock(filename, ACCESS_READ))) { UnLock(lock); return filename; } @@ -2862,7 +2858,7 @@ static void ami_gui_cache_favicon(nsurl *url, struct bitmap *favicon) { STRPTR filename = NULL; - if (filename = ami_gui_get_cache_favicon_name(url, false)) { + if ((filename = ami_gui_get_cache_favicon_name(url, false))) { if(favicon) bitmap_save(favicon, filename, AMI_BITMAP_FORCE_OVERWRITE); FreeVec(filename); } @@ -2896,7 +2892,7 @@ void ami_gui_update_hotlist_button(struct gui_window_2 *gwin) void ami_update_buttons(struct gui_window_2 *gwin) { BOOL back=FALSE,forward=TRUE,tabclose=FALSE,stop=FALSE,reload=FALSE; - uint32 storage = 0; + BOOL storage = FALSE; if(!browser_window_back_available(gwin->bw)) back=TRUE; @@ -2923,29 +2919,29 @@ void ami_update_buttons(struct gui_window_2 *gwin) } } - GetAttr(GA_Disabled, gwin->objects[GID_BACK], &storage); + GetAttr(GA_Disabled, gwin->objects[GID_BACK], (uint32 *)&storage); if(storage != back) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_BACK], gwin->win, NULL, GA_Disabled, back, TAG_DONE); - GetAttr(GA_Disabled, gwin->objects[GID_FORWARD], &storage); + GetAttr(GA_Disabled, gwin->objects[GID_FORWARD], (uint32 *)&storage); if(storage != forward) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_FORWARD], gwin->win, NULL, GA_Disabled, forward, TAG_DONE); - GetAttr(GA_Disabled, gwin->objects[GID_RELOAD], &storage); + GetAttr(GA_Disabled, gwin->objects[GID_RELOAD], (uint32 *)&storage); if(storage != reload) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_RELOAD], gwin->win, NULL, GA_Disabled, reload, TAG_DONE); - GetAttr(GA_Disabled, gwin->objects[GID_STOP], &storage); + GetAttr(GA_Disabled, gwin->objects[GID_STOP], (uint32 *)&storage); if(storage != stop) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_STOP], gwin->win, NULL, GA_Disabled, stop, TAG_DONE); if((gwin->tabs) && (ClickTabBase->lib_Version < 53)) { - GetAttr(GA_Disabled, gwin->objects[GID_CLOSETAB], &storage); + GetAttr(GA_Disabled, gwin->objects[GID_CLOSETAB], (uint32 *)&storage); if(storage != tabclose) SetGadgetAttrs((struct Gadget *)gwin->objects[GID_CLOSETAB], gwin->win, NULL, GA_Disabled, tabclose, TAG_DONE); @@ -3028,7 +3024,7 @@ static void ami_gui_hotlist_toolbar_add(struct gui_window_2 *gwin) } } -void ami_gui_hotlist_toolbar_free(struct gui_window_2 *gwin, struct List *speed_button_list) +static void ami_gui_hotlist_toolbar_free(struct gui_window_2 *gwin, struct List *speed_button_list) { int i; struct Node *node; @@ -3041,8 +3037,8 @@ void ami_gui_hotlist_toolbar_free(struct gui_window_2 *gwin, struct List *speed_ nnode = GetSucc(node); Remove(node); FreeSpeedButtonNode(node); - } while(node = nnode); - + } while((node = nnode)); + for(i = 0; i < AMI_GUI_TOOLBAR_MAX; i++) { if(gwin->hotlist_toolbar_lab[i]) { free(gwin->hotlist_toolbar_lab[i]); @@ -3051,7 +3047,7 @@ void ami_gui_hotlist_toolbar_free(struct gui_window_2 *gwin, struct List *speed_ } } -void ami_gui_hotlist_toolbar_remove(struct gui_window_2 *gwin) +static void ami_gui_hotlist_toolbar_remove(struct gui_window_2 *gwin) { IDoMethod(gwin->objects[GID_HOTLISTLAYOUT], LM_REMOVECHILD, gwin->win, gwin->objects[GID_HOTLIST]); @@ -3067,7 +3063,7 @@ void ami_gui_hotlist_toolbar_remove(struct gui_window_2 *gwin) ami_schedule_redraw(gwin, true); } -void ami_gui_hotlist_toolbar_update(struct gui_window_2 *gwin) +static void ami_gui_hotlist_toolbar_update(struct gui_window_2 *gwin) { if(IsListEmpty(&gwin->hotlist_toolbar_list)) { ami_gui_hotlist_toolbar_add(gwin); @@ -3114,10 +3110,10 @@ void ami_gui_hotlist_update_all(void) ami_gui_hotlist_toolbar_update(gwin); ami_menu_refresh(gwin); } - } while(node = nnode); + } while((node = nnode)); } -void ami_toggletabbar(struct gui_window_2 *gwin, bool show) +static void ami_toggletabbar(struct gui_window_2 *gwin, bool show) { if(ClickTabBase->lib_Version < 53) return; @@ -3200,10 +3196,10 @@ void ami_gui_tabs_toggle_all(void) } } } - } while(node = nnode); + } while((node = nnode)); } -void ami_gui_search_ico_refresh(void *p) +static void ami_gui_search_ico_refresh(void *p) { search_web_select_provider(-1); } @@ -3927,7 +3923,7 @@ void ami_close_all_tabs(struct gui_window_2 *gwin) TNA_UserData,&gwin->bw, TAG_DONE); browser_window_destroy(gwin->bw); - } while(tab=ntab); + } while((tab=ntab)); } else { @@ -3938,7 +3934,7 @@ void ami_close_all_tabs(struct gui_window_2 *gwin) static void gui_window_destroy(struct gui_window *g) { struct Node *ptab; - ULONG ptabnum = 0; + int ptabnum = 0; int gid; if(!g) return; @@ -4049,7 +4045,7 @@ static void gui_window_destroy(struct gui_window *g) static void gui_window_set_title(struct gui_window *g, const char *title) { struct Node *node; - ULONG cur_tab = 0; + int cur_tab = 0; char *utf8title; if(!g) return; @@ -4237,10 +4233,8 @@ static void ami_do_redraw_tiled(struct gui_window_2 *gwin, bool busy, static void ami_do_redraw_limits(struct gui_window *g, struct browser_window *bw, bool busy, int x0, int y0, int x1, int y1) { - ULONG xoffset,yoffset,width=800,height=600; - ULONG htemp,vtemp; struct IBox *bbox; - ULONG cur_tab = 0; + int cur_tab = 0; ULONG sx, sy; struct redraw_context ctx = { @@ -4270,7 +4264,7 @@ static void ami_do_redraw_limits(struct gui_window *g, struct browser_window *bw static void gui_window_redraw_window(struct gui_window *g) { - ULONG cur_tab = 0; + int cur_tab = 0; if(!g) return; @@ -4306,7 +4300,7 @@ static void ami_gui_window_update_box_deferred(struct gui_window *g, bool draw) } nnode=(struct nsObject *)GetSucc((struct Node *)node); DelObject(node); - } while(node = nnode); + } while((node = nnode)); if(draw == true) ami_reset_pointer(g->shared); } @@ -4341,7 +4335,7 @@ struct nsObject *nnode; DelObject(node); /* Don't return - we might find more */ } - } while(node = nnode); + } while((node = nnode)); return true; } @@ -4380,8 +4374,7 @@ static void amiga_window_reformat(struct gui_window *gw) static void ami_do_redraw(struct gui_window_2 *gwin) { - struct Rectangle rect; - ULONG hcurrent,vcurrent,xoffset,yoffset,width=800,height=600,x0=0,y0=0; + ULONG hcurrent,vcurrent,xoffset,yoffset,width=800,height=600; struct IBox *bbox; ULONG oldh = gwin->oldh, oldv=gwin->oldv; struct RastPort *temprp; @@ -4496,7 +4489,7 @@ static void ami_do_redraw(struct gui_window_2 *gwin) gwin->new_content = false; } -void ami_refresh_window(struct gui_window_2 *gwin) +static void ami_refresh_window(struct gui_window_2 *gwin) { /* simplerefresh only */ @@ -4582,7 +4575,7 @@ static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) static void gui_window_set_scroll(struct gui_window *g, int sx, int sy) { struct IBox *bbox; - ULONG cur_tab = 0; + int cur_tab = 0; if(!g) return; if(!g->shared->bw || !g->shared->bw->current_content) return; @@ -4661,7 +4654,7 @@ static void gui_window_get_dimensions(struct gui_window *g, int *width, int *hei static void gui_window_update_extent(struct gui_window *g) { struct IBox *bbox; - ULONG cur_tab = 0; + int cur_tab = 0; if(!g) return; if(!g->shared->bw->current_content) return; @@ -4703,7 +4696,7 @@ static void gui_window_update_extent(struct gui_window *g) static void gui_window_set_status(struct gui_window *g, const char *text) { - ULONG cur_tab = 0; + int cur_tab = 0; char *utf8text; ULONG size; UWORD chars; @@ -4742,7 +4735,7 @@ static void gui_window_set_status(struct gui_window *g, const char *text) static void gui_window_set_url(struct gui_window *g, const char *url) { - ULONG cur_tab = 0; + int cur_tab = 0; if(!g) return; if(!url) return; @@ -4778,8 +4771,6 @@ static nserror gui_search_web_provider_update(const char *provider_name, struct bitmap *ico_bitmap) { struct BitMap *bm = NULL; - struct IBox *bbox; - ULONG cur_tab = 0; struct nsObject *node; struct nsObject *nnode; struct gui_window_2 *gwin; @@ -4815,7 +4806,7 @@ static nserror gui_search_web_provider_update(const char *provider_name, GA_Image, gwin->search_bm, TAG_DONE); } - } while(node = nnode); + } while((node = nnode)); return NSERROR_OK; } @@ -4832,7 +4823,7 @@ static void gui_window_place_caret(struct gui_window *g, int x, int y, int heigh const struct rect *clip) { struct IBox *bbox; - ULONG xs,ys; + int xs,ys; if(!g) return; @@ -4946,7 +4937,7 @@ void ami_scroller_hook(struct Hook *hook,Object *object,struct IntuiMessage *msg break; case GID_HOTLIST: - if(node = (struct Node *)GetTagData(SPEEDBAR_SelectedNode, 0, msg->IAddress)) { + if((node = (struct Node *)GetTagData(SPEEDBAR_SelectedNode, 0, msg->IAddress))) { GetSpeedButtonNodeAttrs(node, SBNA_UserData, (ULONG *)&url, TAG_DONE); if(gwin->key_state & BROWSER_MOUSE_MOD_2) { @@ -5078,14 +5069,14 @@ Object *ami_gui_splash_open(void) tattr.ta_Style = 0; tattr.ta_Flags = 0; - if(tfont = ami_font_open_disk_font(&tattr)) + if((tfont = ami_font_open_disk_font(&tattr))) { SetFont(win->RPort, tfont); } else { tattr.ta_Name = "DejaVu Serif Oblique.font"; - if(tfont = ami_font_open_disk_font(&tattr)) + if((tfont = ami_font_open_disk_font(&tattr))) SetFont(win->RPort, tfont); } @@ -5099,7 +5090,7 @@ Object *ami_gui_splash_open(void) tattr.ta_Style = 0; tattr.ta_Flags = 0; - if(tfont = ami_font_open_disk_font(&tattr)) + if((tfont = ami_font_open_disk_font(&tattr))) SetFont(win->RPort, tfont); ver_string = ASPrintf("%s", netsurf_version); @@ -5241,7 +5232,7 @@ int main(int argc, char** argv) * forcibly disable context menus if these are in use. */ popupmenu_lib_ok = FALSE; - if(PopupMenuBase = OpenLibrary("popupmenu.library", 53)) { + if((PopupMenuBase = OpenLibrary("popupmenu.library", 53))) { LOG(("popupmenu.library v%d.%d", PopupMenuBase->lib_Version, PopupMenuBase->lib_Revision)); if(LIB_IS_AT_LEAST((struct Library *)PopupMenuBase, 53, 11)) @@ -5253,15 +5244,15 @@ int main(int argc, char** argv) current_user = ASPrintf("%s", (user == -1) ? "Default" : temp); current_user_dir = ASPrintf("PROGDIR:Users/%s", current_user); - if(lock = CreateDirTree(current_user_dir)) + if((lock = CreateDirTree(current_user_dir))) UnLock(lock); current_user_options = ASPrintf("%s/Choices", current_user_dir); current_user_cache = ASPrintf("%s/Cache", current_user_dir); current_user_faviconcache = ASPrintf("%s/IconCache", current_user_dir); - if(lock = CreateDirTree(current_user_cache)) UnLock(lock); - if(lock = CreateDirTree(current_user_faviconcache)) UnLock(lock); + if((lock = CreateDirTree(current_user_cache))) UnLock(lock); + if((lock = CreateDirTree(current_user_faviconcache))) UnLock(lock); ami_mime_init("PROGDIR:Resources/mimetypes"); sprintf(temp, "%s/mimetypes.user", current_user_dir); diff --git a/amiga/theme.c b/amiga/theme.c index 047a86e8c..b244056dd 100644 --- a/amiga/theme.c +++ b/amiga/theme.c @@ -178,7 +178,7 @@ void ami_theme_throbber_free(void) throbber = NULL; } -void ami_get_theme_filename(char *filename, char *themestring, bool protocol) +void ami_get_theme_filename(char *filename, const char *themestring, bool protocol) { if(protocol) strcpy(filename,"file:///"); diff --git a/amiga/theme.h b/amiga/theme.h index 083220efc..f295efee1 100644 --- a/amiga/theme.h +++ b/amiga/theme.h @@ -26,7 +26,7 @@ ULONG throbber_width, throbber_height; void ami_theme_init(void); -void ami_get_theme_filename(char *filename, char *themestring, bool protocol); +void ami_get_theme_filename(char *filename, const char *themestring, bool protocol); void ami_theme_throbber_setup(void); void ami_theme_throbber_free(void); diff --git a/atari/ctxmenu.c b/atari/ctxmenu.c index e21876c35..e9c10807a 100644 --- a/atari/ctxmenu.c +++ b/atari/ctxmenu.c @@ -31,7 +31,7 @@ #include "utils/log.h" #include "utils/messages.h" #include "utils/utils.h" -#include "desktop/browser_private.h" +#include "desktop/browser.h" #include "desktop/mouse.h" #include "desktop/textinput.h" #include "content/content.h" @@ -70,7 +70,7 @@ static struct s_context_info * get_context_info( struct gui_window * gw, short m struct browser_window * bw = gw->browser->bw; int sx, sy; - h = bw->current_content; + h = browser_window_get_content(bw); ctxinfo.flags = 0; window_get_grect(gw->root, BROWSER_AREA_CONTENT, &area); @@ -79,7 +79,8 @@ static struct s_context_info * get_context_info( struct gui_window * gw, short m mx -= area.g_x; my -= area.g_y; - if (!bw->current_content || content_get_type(h) != CONTENT_HTML){ + if (browser_window_has_content(bw) == false || + content_get_type(h) != CONTENT_HTML){ return(&ctxinfo); } @@ -231,7 +232,7 @@ void context_popup(struct gui_window * gw, short x, short y) browser_window_navigate( gw->browser->bw, hlcache_handle_get_url(ctx->ccdata.object), - hlcache_handle_get_url(gw->browser->bw->current_content), + browser_window_get_url(gw->browser->bw), BW_NAVIGATE_DOWNLOAD, NULL, NULL, @@ -250,7 +251,7 @@ void context_popup(struct gui_window * gw, short x, short y) error = browser_window_navigate( gw->browser->bw, url, - hlcache_handle_get_url(gw->browser->bw->current_content), + browser_window_get_url(gw->browser->bw), BW_NAVIGATE_DOWNLOAD, NULL, NULL, @@ -290,7 +291,7 @@ void context_popup(struct gui_window * gw, short x, short y) error = browser_window_create( BW_CREATE_HISTORY | BW_CREATE_CLONE, url, - hlcache_handle_get_url(gw->browser->bw->current_content), + browser_window_get_url(gw->browser->bw), gw->browser->bw, NULL ); @@ -305,7 +306,7 @@ void context_popup(struct gui_window * gw, short x, short y) case POP_CTX_VIEW_SOURCE: editor = nsoption_charp(atari_editor); if (editor != NULL && strlen(editor)>0) { - data = content_get_source_data(gw->browser->bw->current_content, + data = content_get_source_data(browser_window_get_content(gw->browser->bw), &size); if (size > 0 && data != NULL){ snprintf(tempfile, 127, "%s", get_tmpfilename("ns-", ".html")); diff --git a/atari/deskmenu.c b/atari/deskmenu.c index 24f4caaed..a9fa6488e 100644 --- a/atari/deskmenu.c +++ b/atari/deskmenu.c @@ -242,8 +242,13 @@ static void __CDECL menu_open_url(short item, short title, void *data) NULL, NULL, &bw); + /** \TODO Should not be accessing inside bw. */ gw = bw->window; } + + /** \TODO Can we do this stuff in gui_window_create, which is called + * in browser_window_create ? */ + /* Loose focus: */ window_set_focus(gw->root, WIDGET_NONE, NULL ); @@ -315,7 +320,8 @@ static void __CDECL menu_save_page(short item, short title, void *data) } while ((is_folder == false) && (path != NULL)); if( path != NULL ){ - save_complete(input_window->browser->bw->current_content, path, NULL); + save_complete(browser_window_get_content( + input_window->browser->bw), path, NULL); } } @@ -513,9 +519,9 @@ static void __CDECL menu_add_bookmark(short item, short title, void *data) { LOG(("%s", __FUNCTION__)); if (input_window) { - if( input_window->browser->bw->current_content != NULL ){ + if( browser_window_has_content(input_window->browser->bw) ){ atari_hotlist_add_page( - nsurl_access(hlcache_handle_get_url(input_window->browser->bw->current_content)), + nsurl_access(browser_window_get_url(input_window->browser->bw)), NULL ); } diff --git a/atari/gui.c b/atari/gui.c index 4ec126ab5..7e5207f94 100644 --- a/atari/gui.c +++ b/atari/gui.c @@ -46,7 +46,6 @@ #include "desktop/textinput.h" #include "desktop/treeview.h" #include "desktop/browser.h" -#include "desktop/browser_private.h" #include "desktop/font.h" #include "desktop/gui_window.h" #include "desktop/gui_clipboard.h" diff --git a/atari/gui.h b/atari/gui.h index 3265759ec..68a416e0f 100755 --- a/atari/gui.h +++ b/atari/gui.h @@ -91,7 +91,7 @@ struct s_focus_info #define CDT_ICON 0x04UL #define CDT_ICON_TYPE 0x05UL # define CDT_ICON_TYPE_NONE 0x00UL -# define CDT_ICON_TYPE_OBJECT 0x01UL
+# define CDT_ICON_TYPE_OBJECT 0x01UL # define CDT_ICON_TYPE_BITMAP 0x02UL @@ -127,9 +127,9 @@ struct s_gui_win_root }; typedef struct s_gui_win_root ROOTWIN; -struct s_browser
-{
- struct browser_window * bw;
+struct s_browser +{ + struct browser_window * bw; bool attached; }; @@ -147,6 +147,7 @@ struct gui_window { char * status; char * title; char * url; + float scale; struct bitmap * icon; struct s_caret caret; struct s_search_form_session *search; diff --git a/atari/rootwin.c b/atari/rootwin.c index 544bb8a65..a35f1791a 100755 --- a/atari/rootwin.c +++ b/atari/rootwin.c @@ -37,7 +37,7 @@ #include <mt_gem.h> #include "utils/log.h" -#include "desktop/browser_private.h" +#include "desktop/browser.h" #include "desktop/mouse.h" #include "desktop/plotters.h" #include "desktop/textinput.h" @@ -286,10 +286,7 @@ int window_create(struct gui_window * gw, assert(gw->browser); gw->browser->bw = bw; - if(existing) - gw->browser->bw->scale = existing->browser->bw->scale; - else - gw->browser->bw->scale = 1; + gw->scale = browser_window_get_scale(bw); /* create statusbar component: */ @@ -663,7 +660,7 @@ void window_open_search(ROOTWIN *rootwin, bool reformat) obj = toolbar_get_form(rootwin->toolbar); if (gw->search == NULL) { - gw->search = nsatari_search_session_create(obj, bw); + gw->search = nsatari_search_session_create(obj, gw); } toolbar_set_visible(rootwin->toolbar, TOOLBAR_AREA_SEARCH, true); @@ -1266,7 +1263,7 @@ static void on_content_mouse_click(ROOTWIN *rootwin) parameter: - unsigned short nkc ( CFLIB normalised key code ) */ -static bool on_content_keypress(struct browser_window *bw, unsigned short nkc) +static bool on_content_keypress(struct gui_window *gw, unsigned short nkc) { bool r = false; unsigned char ascii = (nkc & 0xFF); @@ -1277,15 +1274,15 @@ static bool on_content_keypress(struct browser_window *bw, unsigned short nkc) if (ik == 0) { if (ascii >= 9) { - r = browser_window_key_press(bw, ucs4); + r = browser_window_key_press(gw->browser->bw, ucs4); } } else { - r = browser_window_key_press(bw, ik); + r = browser_window_key_press(gw->browser->bw, ik); if (r == false) { GRECT g; - GUIWIN * w = bw->window->root->win; - window_get_grect(bw->window->root, BROWSER_AREA_CONTENT, &g); + GUIWIN * w = gw->root->win; + window_get_grect(gw->root, BROWSER_AREA_CONTENT, &g); struct gemtk_wm_scroll_info_s *slid = gemtk_wm_get_scroll_info(w); @@ -1335,7 +1332,7 @@ static bool on_content_keypress(struct browser_window *bw, unsigned short nkc) break; case KEY_TEXT_START: - window_scroll_by(bw->window->root, 0, 0); + window_scroll_by(gw->root, 0, 0); r = true; break; @@ -1363,7 +1360,7 @@ static short on_window_key_input(ROOTWIN *rootwin, unsigned short nkc) } else { if( window_widget_has_focus(input_window->root, BROWSER, (void*)input_window->browser)) { - done = on_content_keypress(input_window->browser->bw, nkc); + done = on_content_keypress(input_window, nkc); } else if(window_widget_has_focus(input_window->root, SEARCH_INPUT, NULL)) { OBJECT * obj; @@ -1416,7 +1413,7 @@ static void on_resized(ROOTWIN *rootwin) /* resized */ toolbar_set_width(rootwin->toolbar, work.g_w); - if ( gw->browser->bw->current_content != NULL ) { + if ( browser_window_has_content(gw->browser->bw) ) { browser_window_reformat(gw->browser->bw, true, work.g_w, work.g_h); } } diff --git a/atari/search.c b/atari/search.c index cb2770e88..cd9847bf2 100644 --- a/atari/search.c +++ b/atari/search.c @@ -27,7 +27,7 @@ #include "utils/log.h" #include "utils/messages.h" -#include "desktop/browser_private.h" +#include "desktop/browser.h" #include "desktop/search.h" #include "desktop/gui_search.h" @@ -83,9 +83,9 @@ void nsatari_search_set_hourglass(bool active, void *p) SEARCH_FORM_SESSION s = (SEARCH_FORM_SESSION)p; LOG(("active: %d, session: %p", active, p)); if (active) - gui_window_set_pointer(s->bw->window, GUI_POINTER_PROGRESS); + gui_window_set_pointer(s->g, GUI_POINTER_PROGRESS); else - gui_window_set_pointer(s->bw->window, GUI_POINTER_DEFAULT); + gui_window_set_pointer(s->g, GUI_POINTER_DEFAULT); } /** @@ -117,7 +117,7 @@ void nsatari_search_set_forward_state(bool active, void *p) /* deactivate back cb */ LOG(("%p: set forward state: %d\n", p, active)); - gw = s->bw->window; + gw = s->g; toolbar = toolbar_get_form(gw->root->toolbar); if(active) @@ -145,7 +145,7 @@ void nsatari_search_set_back_state(bool active, void *p) LOG(("%p: set back state: %d\n", p, active)); s->state.back_avail = active; - gw = s->bw->window; + gw = s->g; toolbar = toolbar_get_form(gw->root->toolbar); if(active) @@ -222,7 +222,7 @@ void nsatari_search_session_destroy(struct s_search_form_session *s) { if (s != NULL) { LOG(("")); - browser_window_search_clear(s->bw); + browser_window_search_clear(s->g->browser->bw); free(s); } } @@ -259,11 +259,11 @@ void nsatari_search_perform(struct s_search_form_session *s, OBJECT *obj, search_flags_t f) { assert(s!=null); - assert(input_window->browser->bw == s->bw); + assert(input_window->browser->bw == s->g->browser->bw); if(search_session_compare(s, obj)){ - browser_window_search_clear(s->bw); + browser_window_search_clear(s->g->browser->bw); apply_form(obj, &s->state); } else { @@ -275,7 +275,7 @@ void nsatari_search_perform(struct s_search_form_session *s, OBJECT *obj, else s->state.flags &= (~SEARCH_FLAG_FORWARDS); - browser_window_search(s->bw, s, + browser_window_search(s->g->browser->bw, s, s->state.flags, gemtk_obj_get_text(obj, TOOLBAR_TB_SRCH)); @@ -283,7 +283,7 @@ void nsatari_search_perform(struct s_search_form_session *s, OBJECT *obj, struct s_search_form_session * nsatari_search_session_create(OBJECT * obj, - struct browser_window *bw) + struct gui_window *gw) { struct s_search_form_session *sfs; @@ -292,11 +292,11 @@ struct s_search_form_session * nsatari_search_session_create(OBJECT * obj, assert(obj); assert(sfs); - sfs->bw = bw; + sfs->g = gw; apply_form(obj, &sfs->state); - browser_window_search_clear(bw); + browser_window_search_clear(gw->browser->bw); return(sfs); } diff --git a/atari/search.h b/atari/search.h index 0f427d62c..ee5256778 100644 --- a/atari/search.h +++ b/atari/search.h @@ -32,14 +32,14 @@ struct s_search_form_state { }; struct s_search_form_session { - struct browser_window *bw; + struct gui_window *g; struct s_search_form_state state; }; typedef struct s_search_form_session * SEARCH_FORM_SESSION; struct s_search_form_session * nsatari_search_session_create(OBJECT * obj, - struct browser_window *bw); + struct gui_window *gw); struct gui_search_table *atari_search_table; diff --git a/atari/toolbar.c b/atari/toolbar.c index 9ce7d4b42..56d49de03 100644 --- a/atari/toolbar.c +++ b/atari/toolbar.c @@ -32,7 +32,7 @@ #include "utils/nsurl.h" #include "utils/utf8.h" #include "desktop/browser_history.h" -#include "desktop/browser_private.h" +#include "desktop/browser.h" #include "desktop/mouse.h" #include "desktop/plot_style.h" #include "desktop/plotters.h" diff --git a/beos/window.cpp b/beos/window.cpp index 8202aa14d..71ae3a677 100644 --- a/beos/window.cpp +++ b/beos/window.cpp @@ -23,7 +23,7 @@ extern "C" { #include "content/content.h" #include "content/urldb.h" -#include "desktop/browser_private.h" +#include "desktop/browser.h" #include "desktop/mouse.h" #include "utils/nsoption.h" #include "desktop/textinput.h" @@ -91,6 +91,8 @@ struct gui_window { /* Keep gui_windows in a list for cleanup later */ struct gui_window *next, *prev; + + float scale; }; @@ -334,7 +336,7 @@ struct browser_window *nsbeos_get_browser_for_gui(struct gui_window *g) float nsbeos_get_scale_for_gui(struct gui_window *g) { - return g->bw->scale; + return g->scale; } /* Create a gui_window */ @@ -355,10 +357,7 @@ static struct gui_window *gui_window_create(struct browser_window *bw, g->bw = bw; g->mouse.state = 0; g->current_pointer = GUI_POINTER_DEFAULT; - if (existing != NULL) - bw->scale = existing->bw->scale; - else - bw->scale = (float) nsoption_int(scale) / 100; + g->scale = browser_window_get_scale(bw); g->careth = 0; g->pending_resizes = 0; @@ -515,8 +514,8 @@ void nsbeos_dispatch_event(BMessage *message) gui->mouse.state ^= BROWSER_MOUSE_MOD_2; browser_window_mouse_track(gui->bw, (browser_mouse_state)gui->mouse.state, - (int)(where.x / gui->bw->scale), - (int)(where.y / gui->bw->scale)); + (int)(where.x / gui->scale), + (int)(where.y / gui->scale)); gui->last_x = (int)where.x; gui->last_y = (int)where.y; @@ -559,8 +558,8 @@ void nsbeos_dispatch_event(BMessage *message) if (mods & B_CONTROL_KEY) gui->mouse.state |= BROWSER_MOUSE_MOD_2; - gui->mouse.pressed_x = where.x / gui->bw->scale; - gui->mouse.pressed_y = where.y / gui->bw->scale; + gui->mouse.pressed_x = where.x / gui->scale; + gui->mouse.pressed_y = where.y / gui->scale; // make sure the view is in focus if (view && view->LockLooper()) { @@ -621,8 +620,8 @@ void nsbeos_dispatch_event(BMessage *message) if (gui->mouse.state & (BROWSER_MOUSE_CLICK_1|BROWSER_MOUSE_CLICK_2)) browser_window_mouse_click(gui->bw, (browser_mouse_state)gui->mouse.state, - where.x / gui->bw->scale, - where.y / gui->bw->scale); + where.x / gui->scale, + where.y / gui->scale); else browser_window_mouse_track(gui->bw, (browser_mouse_state)0, where.x, where.y); @@ -680,8 +679,7 @@ void nsbeos_dispatch_event(BMessage *message) void nsbeos_window_expose_event(BView *view, gui_window *g, BMessage *message) { BRect updateRect; - hlcache_handle *c; - float scale = g->bw->scale; + float scale = g->scale; struct rect clip; struct redraw_context ctx = { true, true, &nsbeos_plotters }; @@ -702,8 +700,7 @@ void nsbeos_window_expose_event(BView *view, gui_window *g, BMessage *message) if (message->FindRect("rect", &updateRect) < B_OK) return; - c = g->bw->current_content; - if (c == NULL) + if (browser_window_has_content(g->bw) == false) return; if (!view->LockLooper()) @@ -958,7 +955,6 @@ static void gui_window_destroy(struct gui_window *g) assert(g != NULL); assert(g->bw != NULL); LOG((" Scaffolding: %p", g->scaffold)); - LOG((" Window name: %s", g->bw->name)); if (g->view == NULL) return; @@ -1020,9 +1016,7 @@ static void gui_window_redraw_window(struct gui_window *g) static void gui_window_update_box(struct gui_window *g, const struct rect *rect) { - hlcache_handle *c = g->bw->current_content; - - if (c == NULL) + if (browser_window_has_content(g->bw) == false) return; if (g->view == NULL) @@ -1078,8 +1072,9 @@ static void gui_window_set_scroll(struct gui_window *g, int sx, int sy) static void gui_window_update_extent(struct gui_window *g) { + nserror err; //CALLED(); - if (!g->bw->current_content) + if (browser_window_has_content(g->bw) == false) return; if (g->view == NULL) @@ -1087,8 +1082,12 @@ static void gui_window_update_extent(struct gui_window *g) if (!g->view->LockLooper()) return; - float x_max = content_get_width(g->bw->current_content) * g->bw->scale /* - 1*/; - float y_max = content_get_height(g->bw->current_content) * g->bw->scale /* - 1*/; + int x_max, y_max; + + err = browser_window_get_extents(g->bw, true, &x_max, &y_max); + if (err != NSERROR_OK) + return; + float x_prop = g->view->Bounds().Width() / x_max; float y_prop = g->view->Bounds().Height() / y_max; x_max -= g->view->Bounds().Width() + 1; @@ -1331,8 +1330,8 @@ static void gui_window_get_dimensions(struct gui_window *g, int *width, int *hei } if (scaled) { - *width /= g->bw->scale; - *height /= g->bw->scale; + *width /= g->scale; + *height /= g->scale; } } diff --git a/content/fetch.c b/content/fetch.c index 7923e9af3..2c326e877 100644 --- a/content/fetch.c +++ b/content/fetch.c @@ -287,14 +287,36 @@ static void fetcher_poll(void *unused) /* exported interface documented in content/fetch.h */ nserror fetcher_init(void) { - fetch_curl_register(); - fetch_data_register(); - fetch_file_register(); - fetch_resource_register(); - fetch_about_register(); - fetch_javascript_register(); + nserror ret; - return NSERROR_OK; + ret = fetch_curl_register(); + if (ret != NSERROR_OK) { + return ret; + } + + ret = fetch_data_register(); + if (ret != NSERROR_OK) { + return ret; + } + + ret = fetch_file_register(); + if (ret != NSERROR_OK) { + return ret; + } + + ret = fetch_resource_register(); + if (ret != NSERROR_OK) { + return ret; + } + + ret = fetch_about_register(); + if (ret != NSERROR_OK) { + return ret; + } + + ret = fetch_javascript_register(); + + return ret; } /* exported interface documented in content/fetchers.h */ diff --git a/content/fetchers/about.h b/content/fetchers/about.h index 9544971a6..944f84a59 100644 --- a/content/fetchers/about.h +++ b/content/fetchers/about.h @@ -23,6 +23,11 @@ #ifndef NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H #define NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H +/** + * Register about scheme handler. + * + * \return NSERROR_OK on successful registration or error code on failure. + */ nserror fetch_about_register(void); #endif diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c index df48d8b99..b3a7c6951 100644 --- a/content/fetchers/curl.c +++ b/content/fetchers/curl.c @@ -18,12 +18,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * Fetching of data from an URL (implementation). +/** + * \file + * implementation of fetching of data from http and https schemes. * * This implementation uses libcurl's 'multi' interface. * - * * The CURL handles are cached in the curl_handle_ring. There are at most * ::max_cached_fetch_handles in this ring. */ @@ -106,193 +106,11 @@ static bool curl_with_openssl; static char fetch_error_buffer[CURL_ERROR_SIZE]; /**< Error buffer for cURL. */ static char fetch_proxy_userpwd[100]; /**< Proxy authentication details. */ -static bool fetch_curl_initialise(lwc_string *scheme); -static void fetch_curl_finalise(lwc_string *scheme); -static bool fetch_curl_can_fetch(const nsurl *url); -static void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url, - bool only_2xx, bool downgrade_tls, const char *post_urlenc, - const struct fetch_multipart_data *post_multipart, - const char **headers); -static bool fetch_curl_start(void *vfetch); -static bool fetch_curl_initiate_fetch(struct curl_fetch_info *fetch, - CURL *handle); -static CURL *fetch_curl_get_handle(lwc_string *host); -static void fetch_curl_cache_handle(CURL *handle, lwc_string *host); -static CURLcode fetch_curl_set_options(struct curl_fetch_info *f); -static CURLcode fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx, - void *p); -static void fetch_curl_abort(void *vf); -static void fetch_curl_stop(struct curl_fetch_info *f); -static void fetch_curl_free(void *f); -static void fetch_curl_poll(lwc_string *scheme_ignored); -static void fetch_curl_done(CURL *curl_handle, CURLcode result); -static int fetch_curl_progress(void *clientp, double dltotal, double dlnow, - double ultotal, double ulnow); -static int fetch_curl_ignore_debug(CURL *handle, - curl_infotype type, - char *data, - size_t size, - void *userptr); -static size_t fetch_curl_data(char *data, size_t size, size_t nmemb, - void *_f); -static size_t fetch_curl_header(char *data, size_t size, size_t nmemb, - void *_f); -static bool fetch_curl_process_headers(struct curl_fetch_info *f); -static struct curl_httppost *fetch_curl_post_convert( - const struct fetch_multipart_data *control); -static int fetch_curl_verify_callback(int preverify_ok, - X509_STORE_CTX *x509_ctx); -static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx, - void *parm); - - -/** - * Initialise the fetcher. - * - * Must be called once before any other function. - */ - -void fetch_curl_register(void) -{ - CURLcode code; - curl_version_info_data *data; - int i; - lwc_string *scheme; - const struct fetcher_operation_table fetcher_ops = { - .initialise = fetch_curl_initialise, - .acceptable = fetch_curl_can_fetch, - .setup = fetch_curl_setup, - .start = fetch_curl_start, - .abort = fetch_curl_abort, - .free = fetch_curl_free, - .poll = fetch_curl_poll, - .finalise = fetch_curl_finalise - }; - - LOG(("curl_version %s", curl_version())); - - code = curl_global_init(CURL_GLOBAL_ALL); - if (code != CURLE_OK) - die("Failed to initialise the fetch module " - "(curl_global_init failed)."); - - fetch_curl_multi = curl_multi_init(); - if (!fetch_curl_multi) - die("Failed to initialise the fetch module " - "(curl_multi_init failed)."); - -#if LIBCURL_VERSION_NUM >= 0x071e00 - /* We've been built against 7.30.0 or later: configure caching */ - { - CURLMcode mcode; - int maxconnects = nsoption_int(max_fetchers) + - nsoption_int(max_cached_fetch_handles); - -#undef SETOPT -#define SETOPT(option, value) \ - mcode = curl_multi_setopt(fetch_curl_multi, option, value); \ - if (mcode != CURLM_OK) \ - goto curl_multi_setopt_failed; - - SETOPT(CURLMOPT_MAXCONNECTS, maxconnects); - SETOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, maxconnects); - SETOPT(CURLMOPT_MAX_HOST_CONNECTIONS, nsoption_int(max_fetchers_per_host)); - } -#endif - - /* Create a curl easy handle with the options that are common to all - fetches. */ - fetch_blank_curl = curl_easy_init(); - if (!fetch_blank_curl) - die("Failed to initialise the fetch module " - "(curl_easy_init failed)."); - -#undef SETOPT -#define SETOPT(option, value) \ - code = curl_easy_setopt(fetch_blank_curl, option, value); \ - if (code != CURLE_OK) \ - goto curl_easy_setopt_failed; - - if (verbose_log) { - SETOPT(CURLOPT_VERBOSE, 1); - } else { - SETOPT(CURLOPT_VERBOSE, 0); - } - SETOPT(CURLOPT_ERRORBUFFER, fetch_error_buffer); - if (nsoption_bool(suppress_curl_debug)) { - SETOPT(CURLOPT_DEBUGFUNCTION, fetch_curl_ignore_debug); - } - SETOPT(CURLOPT_WRITEFUNCTION, fetch_curl_data); - SETOPT(CURLOPT_HEADERFUNCTION, fetch_curl_header); - SETOPT(CURLOPT_PROGRESSFUNCTION, fetch_curl_progress); - SETOPT(CURLOPT_NOPROGRESS, 0); - SETOPT(CURLOPT_USERAGENT, user_agent_string()); - SETOPT(CURLOPT_ENCODING, "gzip"); - SETOPT(CURLOPT_LOW_SPEED_LIMIT, 1L); - SETOPT(CURLOPT_LOW_SPEED_TIME, 180L); - SETOPT(CURLOPT_NOSIGNAL, 1L); - SETOPT(CURLOPT_CONNECTTIMEOUT, 30L); - - if (nsoption_charp(ca_bundle) && - strcmp(nsoption_charp(ca_bundle), "")) { - LOG(("ca_bundle: '%s'", nsoption_charp(ca_bundle))); - SETOPT(CURLOPT_CAINFO, nsoption_charp(ca_bundle)); - } - if (nsoption_charp(ca_path) && strcmp(nsoption_charp(ca_path), "")) { - LOG(("ca_path: '%s'", nsoption_charp(ca_path))); - SETOPT(CURLOPT_CAPATH, nsoption_charp(ca_path)); - } - - /* Detect whether the SSL CTX function API works */ - curl_with_openssl = true; - code = curl_easy_setopt(fetch_blank_curl, - CURLOPT_SSL_CTX_FUNCTION, NULL); - if (code != CURLE_OK) { - curl_with_openssl = false; - } - - LOG(("cURL %slinked against openssl", curl_with_openssl ? "" : "not ")); - - /* cURL initialised okay, register the fetchers */ - - data = curl_version_info(CURLVERSION_NOW); - - for (i = 0; data->protocols[i]; i++) { - if (strcmp(data->protocols[i], "http") == 0) { - scheme = lwc_string_ref(corestring_lwc_http); - - } else if (strcmp(data->protocols[i], "https") == 0) { - scheme = lwc_string_ref(corestring_lwc_https); - - } else { - /* Ignore non-http(s) protocols */ - continue; - } - - if (fetcher_add(scheme, &fetcher_ops) != NSERROR_OK) { - LOG(("Unable to register cURL fetcher for %s", - data->protocols[i])); - } - } - return; - -curl_easy_setopt_failed: - die("Failed to initialise the fetch module " - "(curl_easy_setopt failed)."); - -#if LIBCURL_VERSION_NUM >= 0x071e00 -curl_multi_setopt_failed: - die("Failed to initialise the fetch module " - "(curl_multi_setopt failed)."); -#endif -} - /** * Initialise a cURL fetcher. */ - -bool fetch_curl_initialise(lwc_string *scheme) +static bool fetch_curl_initialise(lwc_string *scheme) { LOG(("Initialise cURL fetcher for %s", lwc_string_data(scheme))); curl_fetchers_registered++; @@ -301,10 +119,11 @@ bool fetch_curl_initialise(lwc_string *scheme) /** - * Finalise a cURL fetcher + * Finalise a cURL fetcher. + * + * \param scheme The scheme to finalise. */ - -void fetch_curl_finalise(lwc_string *scheme) +static void fetch_curl_finalise(lwc_string *scheme) { struct cache_handle *h; @@ -334,19 +153,103 @@ void fetch_curl_finalise(lwc_string *scheme) } } -bool fetch_curl_can_fetch(const nsurl *url) + +/** + * Check if this fetcher can fetch a url. + * + * \param url The url to check. + * \return true if teh fetcher supports teh url else false. + */ +static bool fetch_curl_can_fetch(const nsurl *url) { return nsurl_has_component(url, NSURL_HOST); } + +/** + * Convert a list of struct ::fetch_multipart_data to a list of + * struct curl_httppost for libcurl. + */ +static struct curl_httppost * +fetch_curl_post_convert(const struct fetch_multipart_data *control) +{ + struct curl_httppost *post = 0, *last = 0; + CURLFORMcode code; + nserror ret; + + for (; control; control = control->next) { + if (control->file) { + char *leafname = NULL; + ret = guit->file->basename(control->value, &leafname, NULL); + if (ret != NSERROR_OK) { + continue; + } + + /* We have to special case filenames of "", so curl + * a) actually attempts the fetch and + * b) doesn't attempt to open the file "" + */ + if (control->value[0] == '\0') { + /* dummy buffer - needs to be static so + * pointer's still valid when we go out + * of scope (not that libcurl should be + * attempting to access it, of course). + */ + static char buf; + + code = curl_formadd(&post, &last, + CURLFORM_COPYNAME, control->name, + CURLFORM_BUFFER, control->value, + /* needed, as basename("") == "." */ + CURLFORM_FILENAME, "", + CURLFORM_BUFFERPTR, &buf, + CURLFORM_BUFFERLENGTH, 0, + CURLFORM_CONTENTTYPE, + "application/octet-stream", + CURLFORM_END); + if (code != CURL_FORMADD_OK) + LOG(("curl_formadd: %d (%s)", + code, control->name)); + } else { + char *mimetype = guit->fetch->mimetype(control->value); + code = curl_formadd(&post, &last, + CURLFORM_COPYNAME, control->name, + CURLFORM_FILE, control->rawfile, + CURLFORM_FILENAME, leafname, + CURLFORM_CONTENTTYPE, + (mimetype != 0 ? mimetype : "text/plain"), + CURLFORM_END); + if (code != CURL_FORMADD_OK) + LOG(("curl_formadd: %d (%s=%s)", + code, control->name, + control->value)); + free(mimetype); + } + free(leafname); + } + else { + code = curl_formadd(&post, &last, + CURLFORM_COPYNAME, control->name, + CURLFORM_COPYCONTENTS, control->value, + CURLFORM_END); + if (code != CURL_FORMADD_OK) + LOG(("curl_formadd: %d (%s=%s)", code, + control->name, + control->value)); + } + } + + return post; +} + /** * Start fetching data for the given URL. * * The function returns immediately. The fetch may be queued for later * processing. * - * A pointer to an opaque struct curl_fetch_info is returned, which can be - * passed to fetch_abort() to abort the fetch at any time. Returns 0 if memory + * A pointer to an opaque struct curl_fetch_info is returned, which can be + * passed to fetch_abort() to abort the fetch at any time. Returns 0 if memory * is exhausted (or some other fatal error occurred). * * The caller must supply a callback function which is called when anything @@ -360,9 +263,12 @@ bool fetch_curl_can_fetch(const nsurl *url) * Some private data can be passed as the last parameter to fetch_start, and * callbacks will contain this. */ - -void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url, - bool only_2xx, bool downgrade_tls, const char *post_urlenc, +static void * +fetch_curl_setup(struct fetch *parent_fetch, + nsurl *url, + bool only_2xx, + bool downgrade_tls, + const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { @@ -420,7 +326,7 @@ void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url, * which fails with lighttpd, so disable it (see bug 1429054) */ APPEND(fetch->headers, "Expect:"); - if ((nsoption_charp(accept_language) != NULL) && + if ((nsoption_charp(accept_language) != NULL) && (nsoption_charp(accept_language)[0] != '\0')) { char s[80]; snprintf(s, sizeof s, "Accept-Language: %s, *;q=0.1", @@ -429,7 +335,7 @@ void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url, APPEND(fetch->headers, s); } - if (nsoption_charp(accept_charset) != NULL && + if (nsoption_charp(accept_charset) != NULL && nsoption_charp(accept_charset)[0] != '\0') { char s[80]; snprintf(s, sizeof s, "Accept-Charset: %s, *;q=0.1", @@ -449,6 +355,8 @@ void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url, return fetch; +#undef APPEND + failed: if (fetch->host != NULL) lwc_string_unref(fetch->host); @@ -464,126 +372,96 @@ failed: /** - * Dispatch a single job + * OpenSSL Certificate verification callback + * Stores certificate details in fetch struct. */ -bool fetch_curl_start(void *vfetch) +static int +fetch_curl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { - struct curl_fetch_info *fetch = (struct curl_fetch_info*)vfetch; - return fetch_curl_initiate_fetch(fetch, - fetch_curl_get_handle(fetch->host)); + X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx); + int depth = X509_STORE_CTX_get_error_depth(x509_ctx); + int err = X509_STORE_CTX_get_error(x509_ctx); + struct curl_fetch_info *f = X509_STORE_CTX_get_app_data(x509_ctx); + + /* save the certificate by incrementing the reference count and + * keeping a pointer. + */ + if (depth < MAX_CERTS && !f->cert_data[depth].cert) { + f->cert_data[depth].cert = cert; + f->cert_data[depth].err = err; + cert->references++; + } + + return preverify_ok; } /** - * Initiate a fetch from the queue. - * - * Called with a fetch structure and a CURL handle to be used to fetch the - * content. - * - * This will return whether or not the fetch was successfully initiated. + * OpenSSL certificate chain verification callback + * Verifies certificate chain, setting up context for fetch_curl_verify_callback */ - -bool fetch_curl_initiate_fetch(struct curl_fetch_info *fetch, CURL *handle) +static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm) { - CURLcode code; - CURLMcode codem; - - fetch->curl_handle = handle; + int ok; - /* Initialise the handle */ - code = fetch_curl_set_options(fetch); - if (code != CURLE_OK) { - fetch->curl_handle = 0; - return false; - } + /* Store fetch struct in context for verify callback */ + ok = X509_STORE_CTX_set_app_data(x509_ctx, parm); - /* add to the global curl multi handle */ - codem = curl_multi_add_handle(fetch_curl_multi, fetch->curl_handle); - assert(codem == CURLM_OK || codem == CURLM_CALL_MULTI_PERFORM); + /* and verify the certificate chain */ + if (ok) + ok = X509_verify_cert(x509_ctx); - return true; + return ok; } /** - * Find a CURL handle to use to dispatch a job + * cURL SSL setup callback + * + * \param curl_handle The curl handle to perform the ssl operation on. + * \param _sslctx The ssl context. + * \param parm The callback context. + * \return A curl result code. */ - -CURL *fetch_curl_get_handle(lwc_string *host) +static CURLcode +fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx, void *parm) { - struct cache_handle *h; - CURL *ret; - RING_FINDBYLWCHOST(curl_handle_ring, h, host); - if (h) { - ret = h->handle; - lwc_string_unref(h->host); - RING_REMOVE(curl_handle_ring, h); - free(h); - } else { - ret = curl_easy_duphandle(fetch_blank_curl); - } - return ret; -} - + struct curl_fetch_info *f = (struct curl_fetch_info *) parm; + SSL_CTX *sslctx = _sslctx; + long options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; -/** - * Cache a CURL handle for the provided host (if wanted) - */ + SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, fetch_curl_verify_callback); + SSL_CTX_set_cert_verify_callback(sslctx, + fetch_curl_cert_verify_callback, + parm); -void fetch_curl_cache_handle(CURL *handle, lwc_string *host) -{ -#if LIBCURL_VERSION_NUM >= 0x071e00 - /* 7.30.0 or later has its own connection caching; suppress ours */ - curl_easy_cleanup(handle); - return; -#else - struct cache_handle *h = 0; - int c; - RING_FINDBYLWCHOST(curl_handle_ring, h, host); - if (h) { - /* Already have a handle cached for this hostname */ - curl_easy_cleanup(handle); - return; + if (f->downgrade_tls) { + /* Disable TLS 1.1/1.2 if the server can't cope with them */ +#ifdef SSL_OP_NO_TLSv1_1 + options |= SSL_OP_NO_TLSv1_1; +#endif +#ifdef SSL_OP_NO_TLSv1_2 + options |= SSL_OP_NO_TLSv1_2; +#endif +#ifdef SSL_MODE_SEND_FALLBACK_SCSV + /* Ensure server rejects the connection if downgraded too far */ + SSL_CTX_set_mode(sslctx, SSL_MODE_SEND_FALLBACK_SCSV); +#endif } - /* We do not have a handle cached, first up determine if the cache is full */ - RING_GETSIZE(struct cache_handle, curl_handle_ring, c); - if (c >= nsoption_int(max_cached_fetch_handles)) { - /* Cache is full, so, we rotate the ring by one and - * replace the oldest handle with this one. We do this - * without freeing/allocating memory (except the - * hostname) and without removing the entry from the - * ring and then re-inserting it, in order to be as - * efficient as we can. - */ - if (curl_handle_ring != NULL) { - h = curl_handle_ring; - curl_handle_ring = h->r_next; - curl_easy_cleanup(h->handle); - h->handle = handle; - lwc_string_unref(h->host); - h->host = lwc_string_ref(host); - } else { - /* Actually, we don't want to cache any handles */ - curl_easy_cleanup(handle); - } - return; - } - /* The table isn't full yet, so make a shiny new handle to add to the ring */ - h = (struct cache_handle*)malloc(sizeof(struct cache_handle)); - h->handle = handle; - h->host = lwc_string_ref(host); - RING_INSERT(curl_handle_ring, h); -#endif + SSL_CTX_set_options(sslctx, options); + + return CURLE_OK; } /** * Set options specific for a fetch. + * + * \param f The fetch to set options on. + * \return A curl result code. */ - -CURLcode -fetch_curl_set_options(struct curl_fetch_info *f) +static CURLcode fetch_curl_set_options(struct curl_fetch_info *f) { CURLcode code; const char *auth; @@ -631,7 +509,7 @@ fetch_curl_set_options(struct curl_fetch_info *f) } /* set up proxy options */ - if (nsoption_bool(http_proxy) && + if (nsoption_bool(http_proxy) && (nsoption_charp(http_proxy_host) != NULL) && (strncmp(nsurl_access(f->url), "file:", 5) != 0)) { SETOPT(CURLOPT_PROXY, nsoption_charp(http_proxy_host)); @@ -684,47 +562,122 @@ fetch_curl_set_options(struct curl_fetch_info *f) return CURLE_OK; } +/** + * Initiate a fetch from the queue. + * + * \param fetch fetch to use to fetch content. + * \param handle CURL handle to be used to fetch the content. + * \return true if the fetch was successfully initiated else false. + */ +static bool +fetch_curl_initiate_fetch(struct curl_fetch_info *fetch, CURL *handle) +{ + CURLcode code; + CURLMcode codem; + + fetch->curl_handle = handle; + + /* Initialise the handle */ + code = fetch_curl_set_options(fetch); + if (code != CURLE_OK) { + fetch->curl_handle = 0; + return false; + } + + /* add to the global curl multi handle */ + codem = curl_multi_add_handle(fetch_curl_multi, fetch->curl_handle); + assert(codem == CURLM_OK || codem == CURLM_CALL_MULTI_PERFORM); + + return true; +} + /** - * cURL SSL setup callback + * Find a CURL handle to use to dispatch a job */ +static CURL *fetch_curl_get_handle(lwc_string *host) +{ + struct cache_handle *h; + CURL *ret; + RING_FINDBYLWCHOST(curl_handle_ring, h, host); + if (h) { + ret = h->handle; + lwc_string_unref(h->host); + RING_REMOVE(curl_handle_ring, h); + free(h); + } else { + ret = curl_easy_duphandle(fetch_blank_curl); + } + return ret; +} -CURLcode -fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx, void *parm) + +/** + * Dispatch a single job + */ +static bool fetch_curl_start(void *vfetch) { - struct curl_fetch_info *f = (struct curl_fetch_info *) parm; - SSL_CTX *sslctx = _sslctx; - long options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + struct curl_fetch_info *fetch = (struct curl_fetch_info*)vfetch; + return fetch_curl_initiate_fetch(fetch, + fetch_curl_get_handle(fetch->host)); +} - SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, fetch_curl_verify_callback); - SSL_CTX_set_cert_verify_callback(sslctx, fetch_curl_cert_verify_callback, - parm); +/** + * Cache a CURL handle for the provided host (if wanted) + */ - if (f->downgrade_tls) { - /* Disable TLS 1.1/1.2 if the server can't cope with them */ -#ifdef SSL_OP_NO_TLSv1_1 - options |= SSL_OP_NO_TLSv1_1; -#endif -#ifdef SSL_OP_NO_TLSv1_2 - options |= SSL_OP_NO_TLSv1_2; -#endif -#ifdef SSL_MODE_SEND_FALLBACK_SCSV - /* Ensure server rejects the connection if downgraded too far */ - SSL_CTX_set_mode(sslctx, SSL_MODE_SEND_FALLBACK_SCSV); -#endif +static void fetch_curl_cache_handle(CURL *handle, lwc_string *host) +{ +#if LIBCURL_VERSION_NUM >= 0x071e00 + /* 7.30.0 or later has its own connection caching; suppress ours */ + curl_easy_cleanup(handle); + return; +#else + struct cache_handle *h = 0; + int c; + RING_FINDBYLWCHOST(curl_handle_ring, h, host); + if (h) { + /* Already have a handle cached for this hostname */ + curl_easy_cleanup(handle); + return; } + /* We do not have a handle cached, first up determine if the cache is full */ + RING_GETSIZE(struct cache_handle, curl_handle_ring, c); + if (c >= nsoption_int(max_cached_fetch_handles)) { + /* Cache is full, so, we rotate the ring by one and + * replace the oldest handle with this one. We do this + * without freeing/allocating memory (except the + * hostname) and without removing the entry from the + * ring and then re-inserting it, in order to be as + * efficient as we can. + */ + if (curl_handle_ring != NULL) { + h = curl_handle_ring; + curl_handle_ring = h->r_next; + curl_easy_cleanup(h->handle); + h->handle = handle; + lwc_string_unref(h->host); + h->host = lwc_string_ref(host); + } else { + /* Actually, we don't want to cache any handles */ + curl_easy_cleanup(handle); + } - SSL_CTX_set_options(sslctx, options); - - return CURLE_OK; + return; + } + /* The table isn't full yet, so make a shiny new handle to add to the ring */ + h = (struct cache_handle*)malloc(sizeof(struct cache_handle)); + h->handle = handle; + h->host = lwc_string_ref(host); + RING_INSERT(curl_handle_ring, h); +#endif } /** * Abort a fetch. */ - -void fetch_curl_abort(void *vf) +static void fetch_curl_abort(void *vf) { struct curl_fetch_info *f = (struct curl_fetch_info *)vf; assert(f); @@ -743,8 +696,7 @@ void fetch_curl_abort(void *vf) * * Will prod the queue afterwards to allow pending requests to be initiated. */ - -void fetch_curl_stop(struct curl_fetch_info *f) +static void fetch_curl_stop(struct curl_fetch_info *f) { CURLMcode codem; @@ -768,8 +720,7 @@ void fetch_curl_stop(struct curl_fetch_info *f) /** * Free a fetch structure and associated resources. */ - -void fetch_curl_free(void *vf) +static void fetch_curl_free(void *vf) { struct curl_fetch_info *f = (struct curl_fetch_info *)vf; int i; @@ -798,41 +749,65 @@ void fetch_curl_free(void *vf) /** - * Do some work on current fetches. + * Find the status code and content type and inform the caller. * - * Must be called regularly to make progress on fetches. + * Return true if the fetch is being aborted. */ - -void fetch_curl_poll(lwc_string *scheme_ignored) +static bool fetch_curl_process_headers(struct curl_fetch_info *f) { - int running, queue; - CURLMcode codem; - CURLMsg *curl_msg; - - /* do any possible work on the current fetches */ - do { - codem = curl_multi_perform(fetch_curl_multi, &running); - if (codem != CURLM_OK && codem != CURLM_CALL_MULTI_PERFORM) { - LOG(("curl_multi_perform: %i %s", - codem, curl_multi_strerror(codem))); - warn_user("MiscError", curl_multi_strerror(codem)); - return; - } - } while (codem == CURLM_CALL_MULTI_PERFORM); + long http_code; + CURLcode code; + fetch_msg msg; - /* process curl results */ - curl_msg = curl_multi_info_read(fetch_curl_multi, &queue); - while (curl_msg) { - switch (curl_msg->msg) { - case CURLMSG_DONE: - fetch_curl_done(curl_msg->easy_handle, - curl_msg->data.result); - break; - default: - break; - } - curl_msg = curl_multi_info_read(fetch_curl_multi, &queue); + f->had_headers = true; + + if (!f->http_code) + { + code = curl_easy_getinfo(f->curl_handle, CURLINFO_HTTP_CODE, + &f->http_code); + fetch_set_http_code(f->fetch_handle, f->http_code); + assert(code == CURLE_OK); + } + http_code = f->http_code; + LOG(("HTTP status code %li", http_code)); + + if (http_code == 304 && !f->post_urlenc && !f->post_multipart) { + /* Not Modified && GET request */ + msg.type = FETCH_NOTMODIFIED; + fetch_send_callback(&msg, f->fetch_handle); + return true; } + + /* handle HTTP redirects (3xx response codes) */ + if (300 <= http_code && http_code < 400 && f->location != 0) { + LOG(("FETCH_REDIRECT, '%s'", f->location)); + msg.type = FETCH_REDIRECT; + msg.data.redirect = f->location; + fetch_send_callback(&msg, f->fetch_handle); + return true; + } + + /* handle HTTP 401 (Authentication errors) */ + if (http_code == 401) { + msg.type = FETCH_AUTH; + msg.data.auth.realm = f->realm; + fetch_send_callback(&msg, f->fetch_handle); + return true; + } + + /* handle HTTP errors (non 2xx response codes) */ + if (f->only_2xx && strncmp(nsurl_access(f->url), "http", 4) == 0 && + (http_code < 200 || 299 < http_code)) { + msg.type = FETCH_ERROR; + msg.data.error = messages_get("Not2xx"); + fetch_send_callback(&msg, f->fetch_handle); + return true; + } + + if (f->abort) + return true; + + return false; } @@ -841,8 +816,7 @@ void fetch_curl_poll(lwc_string *scheme_ignored) * * \param curl_handle curl easy handle of fetch */ - -void fetch_curl_done(CURL *curl_handle, CURLcode result) +static void fetch_curl_done(CURL *curl_handle, CURLcode result) { fetch_msg msg; bool finished = false; @@ -865,14 +839,15 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result) if (abort_fetch == false && (result == CURLE_OK || (result == CURLE_WRITE_ERROR && f->stopped == false))) { - /* fetch completed normally or the server fed us a junk gzip - * stream (usually in the form of garbage at the end of the - * stream). Curl will have fed us all but the last chunk of - * decoded data, which is sad as, if we'd received the last + /* fetch completed normally or the server fed us a junk gzip + * stream (usually in the form of garbage at the end of the + * stream). Curl will have fed us all but the last chunk of + * decoded data, which is sad as, if we'd received the last * chunk, too, we'd be able to render the whole object. * As is, we'll just have to accept that the end of the * object will be truncated in this case and leave it to - * the content handlers to cope. */ + * the content handlers to cope. + */ if (f->stopped || (!f->had_headers && fetch_curl_process_headers(f))) @@ -1017,10 +992,50 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result) /** + * Do some work on current fetches. + * + * Must be called regularly to make progress on fetches. + */ +static void fetch_curl_poll(lwc_string *scheme_ignored) +{ + int running, queue; + CURLMcode codem; + CURLMsg *curl_msg; + + /* do any possible work on the current fetches */ + do { + codem = curl_multi_perform(fetch_curl_multi, &running); + if (codem != CURLM_OK && codem != CURLM_CALL_MULTI_PERFORM) { + LOG(("curl_multi_perform: %i %s", + codem, curl_multi_strerror(codem))); + warn_user("MiscError", curl_multi_strerror(codem)); + return; + } + } while (codem == CURLM_CALL_MULTI_PERFORM); + + /* process curl results */ + curl_msg = curl_multi_info_read(fetch_curl_multi, &queue); + while (curl_msg) { + switch (curl_msg->msg) { + case CURLMSG_DONE: + fetch_curl_done(curl_msg->easy_handle, + curl_msg->data.result); + break; + default: + break; + } + curl_msg = curl_multi_info_read(fetch_curl_multi, &queue); + } +} + + + + +/** * Callback function for fetch progress. */ -int fetch_curl_progress(void *clientp, double dltotal, double dlnow, +static int fetch_curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { static char fetch_progress_buffer[256]; /**< Progress buffer for cURL */ @@ -1061,14 +1076,12 @@ int fetch_curl_progress(void *clientp, double dltotal, double dlnow, } - /** * Ignore everything given to it. * * Used to ignore cURL debug. */ - -int fetch_curl_ignore_debug(CURL *handle, +static int fetch_curl_ignore_debug(CURL *handle, curl_infotype type, char *data, size_t size, @@ -1081,9 +1094,7 @@ int fetch_curl_ignore_debug(CURL *handle, /** * Callback function for cURL. */ - -size_t fetch_curl_data(char *data, size_t size, size_t nmemb, - void *_f) +static size_t fetch_curl_data(char *data, size_t size, size_t nmemb, void *_f) { struct curl_fetch_info *f = _f; CURLcode code; @@ -1099,7 +1110,8 @@ size_t fetch_curl_data(char *data, size_t size, size_t nmemb, } /* ignore body if this is a 401 reply by skipping it and reset - the HTTP response code to enable follow up fetches */ + * the HTTP response code to enable follow up fetches. + */ if (f->http_code == 401) { f->http_code = 0; @@ -1131,8 +1143,7 @@ size_t fetch_curl_data(char *data, size_t size, size_t nmemb, * * See RFC 2616 4.2. */ - -size_t fetch_curl_header(char *data, size_t size, size_t nmemb, +static size_t fetch_curl_header(char *data, size_t size, size_t nmemb, void *_f) { struct curl_fetch_info *f = _f; @@ -1211,185 +1222,144 @@ size_t fetch_curl_header(char *data, size_t size, size_t nmemb, #undef SKIP_ST } -/** - * Find the status code and content type and inform the caller. - * - * Return true if the fetch is being aborted. - */ -bool fetch_curl_process_headers(struct curl_fetch_info *f) +/* exported function documented in content/fetchers/curl.h */ +nserror fetch_curl_register(void) { - long http_code; CURLcode code; - fetch_msg msg; + curl_version_info_data *data; + int i; + lwc_string *scheme; + const struct fetcher_operation_table fetcher_ops = { + .initialise = fetch_curl_initialise, + .acceptable = fetch_curl_can_fetch, + .setup = fetch_curl_setup, + .start = fetch_curl_start, + .abort = fetch_curl_abort, + .free = fetch_curl_free, + .poll = fetch_curl_poll, + .finalise = fetch_curl_finalise + }; - f->had_headers = true; + LOG(("curl_version %s", curl_version())); - if (!f->http_code) - { - code = curl_easy_getinfo(f->curl_handle, CURLINFO_HTTP_CODE, - &f->http_code); - fetch_set_http_code(f->fetch_handle, f->http_code); - assert(code == CURLE_OK); + code = curl_global_init(CURL_GLOBAL_ALL); + if (code != CURLE_OK) { + LOG(("curl_global_init failed.")); + return NSERROR_INIT_FAILED; } - http_code = f->http_code; - LOG(("HTTP status code %li", http_code)); - if (http_code == 304 && !f->post_urlenc && !f->post_multipart) { - /* Not Modified && GET request */ - msg.type = FETCH_NOTMODIFIED; - fetch_send_callback(&msg, f->fetch_handle); - return true; + fetch_curl_multi = curl_multi_init(); + if (!fetch_curl_multi) { + LOG(("curl_multi_init failed.")); + return NSERROR_INIT_FAILED; } - /* handle HTTP redirects (3xx response codes) */ - if (300 <= http_code && http_code < 400 && f->location != 0) { - LOG(("FETCH_REDIRECT, '%s'", f->location)); - msg.type = FETCH_REDIRECT; - msg.data.redirect = f->location; - fetch_send_callback(&msg, f->fetch_handle); - return true; - } +#if LIBCURL_VERSION_NUM >= 0x071e00 + /* built against 7.30.0 or later: configure caching */ + { + CURLMcode mcode; + int maxconnects = nsoption_int(max_fetchers) + + nsoption_int(max_cached_fetch_handles); - /* handle HTTP 401 (Authentication errors) */ - if (http_code == 401) { - msg.type = FETCH_AUTH; - msg.data.auth.realm = f->realm; - fetch_send_callback(&msg, f->fetch_handle); - return true; - } +#undef SETOPT +#define SETOPT(option, value) \ + mcode = curl_multi_setopt(fetch_curl_multi, option, value); \ + if (mcode != CURLM_OK) \ + goto curl_multi_setopt_failed; - /* handle HTTP errors (non 2xx response codes) */ - if (f->only_2xx && strncmp(nsurl_access(f->url), "http", 4) == 0 && - (http_code < 200 || 299 < http_code)) { - msg.type = FETCH_ERROR; - msg.data.error = messages_get("Not2xx"); - fetch_send_callback(&msg, f->fetch_handle); - return true; + SETOPT(CURLMOPT_MAXCONNECTS, maxconnects); + SETOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, maxconnects); + SETOPT(CURLMOPT_MAX_HOST_CONNECTIONS, nsoption_int(max_fetchers_per_host)); } +#endif - if (f->abort) - return true; - - return false; -} - - -/** - * Convert a list of struct ::fetch_multipart_data to a list of - * struct curl_httppost for libcurl. - */ -struct curl_httppost * -fetch_curl_post_convert(const struct fetch_multipart_data *control) -{ - struct curl_httppost *post = 0, *last = 0; - CURLFORMcode code; - nserror ret; - - for (; control; control = control->next) { - if (control->file) { - char *leafname = NULL; - ret = guit->file->basename(control->value, &leafname, NULL); - if (ret != NSERROR_OK) { - continue; - } + /* Create a curl easy handle with the options that are common to all + fetches. + */ + fetch_blank_curl = curl_easy_init(); + if (!fetch_blank_curl) { + LOG(("curl_easy_init failed")); + return NSERROR_INIT_FAILED; + } - /* We have to special case filenames of "", so curl - * a) actually attempts the fetch and - * b) doesn't attempt to open the file "" - */ - if (control->value[0] == '\0') { - /* dummy buffer - needs to be static so - * pointer's still valid when we go out - * of scope (not that libcurl should be - * attempting to access it, of course). */ - static char buf; +#undef SETOPT +#define SETOPT(option, value) \ + code = curl_easy_setopt(fetch_blank_curl, option, value); \ + if (code != CURLE_OK) \ + goto curl_easy_setopt_failed; - code = curl_formadd(&post, &last, - CURLFORM_COPYNAME, control->name, - CURLFORM_BUFFER, control->value, - /* needed, as basename("") == "." */ - CURLFORM_FILENAME, "", - CURLFORM_BUFFERPTR, &buf, - CURLFORM_BUFFERLENGTH, 0, - CURLFORM_CONTENTTYPE, - "application/octet-stream", - CURLFORM_END); - if (code != CURL_FORMADD_OK) - LOG(("curl_formadd: %d (%s)", - code, control->name)); - } else { - char *mimetype = guit->fetch->mimetype(control->value); - code = curl_formadd(&post, &last, - CURLFORM_COPYNAME, control->name, - CURLFORM_FILE, control->rawfile, - CURLFORM_FILENAME, leafname, - CURLFORM_CONTENTTYPE, - (mimetype != 0 ? mimetype : "text/plain"), - CURLFORM_END); - if (code != CURL_FORMADD_OK) - LOG(("curl_formadd: %d (%s=%s)", - code, control->name, - control->value)); - free(mimetype); - } - free(leafname); - } - else { - code = curl_formadd(&post, &last, - CURLFORM_COPYNAME, control->name, - CURLFORM_COPYCONTENTS, control->value, - CURLFORM_END); - if (code != CURL_FORMADD_OK) - LOG(("curl_formadd: %d (%s=%s)", code, - control->name, - control->value)); - } + if (verbose_log) { + SETOPT(CURLOPT_VERBOSE, 1); + } else { + SETOPT(CURLOPT_VERBOSE, 0); + } + SETOPT(CURLOPT_ERRORBUFFER, fetch_error_buffer); + if (nsoption_bool(suppress_curl_debug)) { + SETOPT(CURLOPT_DEBUGFUNCTION, fetch_curl_ignore_debug); } + SETOPT(CURLOPT_WRITEFUNCTION, fetch_curl_data); + SETOPT(CURLOPT_HEADERFUNCTION, fetch_curl_header); + SETOPT(CURLOPT_PROGRESSFUNCTION, fetch_curl_progress); + SETOPT(CURLOPT_NOPROGRESS, 0); + SETOPT(CURLOPT_USERAGENT, user_agent_string()); + SETOPT(CURLOPT_ENCODING, "gzip"); + SETOPT(CURLOPT_LOW_SPEED_LIMIT, 1L); + SETOPT(CURLOPT_LOW_SPEED_TIME, 180L); + SETOPT(CURLOPT_NOSIGNAL, 1L); + SETOPT(CURLOPT_CONNECTTIMEOUT, 30L); - return post; -} + if (nsoption_charp(ca_bundle) && + strcmp(nsoption_charp(ca_bundle), "")) { + LOG(("ca_bundle: '%s'", nsoption_charp(ca_bundle))); + SETOPT(CURLOPT_CAINFO, nsoption_charp(ca_bundle)); + } + if (nsoption_charp(ca_path) && strcmp(nsoption_charp(ca_path), "")) { + LOG(("ca_path: '%s'", nsoption_charp(ca_path))); + SETOPT(CURLOPT_CAPATH, nsoption_charp(ca_path)); + } + /* Detect whether the SSL CTX function API works */ + curl_with_openssl = true; + code = curl_easy_setopt(fetch_blank_curl, + CURLOPT_SSL_CTX_FUNCTION, NULL); + if (code != CURLE_OK) { + curl_with_openssl = false; + } -/** - * OpenSSL Certificate verification callback - * Stores certificate details in fetch struct. - */ + LOG(("cURL %slinked against openssl", curl_with_openssl ? "" : "not ")); -int fetch_curl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) -{ - X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx); - int depth = X509_STORE_CTX_get_error_depth(x509_ctx); - int err = X509_STORE_CTX_get_error(x509_ctx); - struct curl_fetch_info *f = X509_STORE_CTX_get_app_data(x509_ctx); + /* cURL initialised okay, register the fetchers */ - /* save the certificate by incrementing the reference count and - * keeping a pointer */ - if (depth < MAX_CERTS && !f->cert_data[depth].cert) { - f->cert_data[depth].cert = cert; - f->cert_data[depth].err = err; - cert->references++; - } + data = curl_version_info(CURLVERSION_NOW); - return preverify_ok; -} + for (i = 0; data->protocols[i]; i++) { + if (strcmp(data->protocols[i], "http") == 0) { + scheme = lwc_string_ref(corestring_lwc_http); + } else if (strcmp(data->protocols[i], "https") == 0) { + scheme = lwc_string_ref(corestring_lwc_https); -/** - * OpenSSL certificate chain verification callback - * Verifies certificate chain, setting up context for fetch_curl_verify_callback - */ + } else { + /* Ignore non-http(s) protocols */ + continue; + } -int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm) -{ - int ok; + if (fetcher_add(scheme, &fetcher_ops) != NSERROR_OK) { + LOG(("Unable to register cURL fetcher for %s", + data->protocols[i])); + } + } - /* Store fetch struct in context for verify callback */ - ok = X509_STORE_CTX_set_app_data(x509_ctx, parm); + return NSERROR_OK; - /* and verify the certificate chain */ - if (ok) - ok = X509_verify_cert(x509_ctx); +curl_easy_setopt_failed: + LOG(("curl_easy_setopt failed.")); + return NSERROR_INIT_FAILED; - return ok; +#if LIBCURL_VERSION_NUM >= 0x071e00 +curl_multi_setopt_failed: + LOG(("curl_multi_setopt failed.")); + return NSERROR_INIT_FAILED; +#endif } diff --git a/content/fetchers/curl.h b/content/fetchers/curl.h index 7ee096349..5f2446a91 100644 --- a/content/fetchers/curl.h +++ b/content/fetchers/curl.h @@ -25,7 +25,12 @@ #include <curl/curl.h> -void fetch_curl_register(void); +/** + * Register curl scheme handler. + * + * \return NSERROR_OK on successful registration or error code on failure. + */ +nserror fetch_curl_register(void); /** Global cURL multi handle. */ extern CURLM *fetch_curl_multi; diff --git a/content/fetchers/data.h b/content/fetchers/data.h index f6017e07a..2f89ecf54 100644 --- a/content/fetchers/data.h +++ b/content/fetchers/data.h @@ -16,13 +16,19 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * data: URL method handler +/** + * \file + * data scheme fetch handler interface. */ #ifndef NETSURF_CONTENT_FETCHERS_FETCH_DATA_H #define NETSURF_CONTENT_FETCHERS_FETCH_DATA_H +/** + * Register data scheme handler. + * + * \return NSERROR_OK on successful registration or error code on failure. + */ nserror fetch_data_register(void); #endif diff --git a/content/fetchers/file.h b/content/fetchers/file.h index b3c39db9f..5a5cfe89b 100644 --- a/content/fetchers/file.h +++ b/content/fetchers/file.h @@ -16,13 +16,19 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * file: URL method handler +/** + * \file + * file scheme fetcher handler interface. */ #ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H #define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H +/** + * Register file scheme handler. + * + * \return NSERROR_OK on successful registration or error code on failure. + */ nserror fetch_file_register(void); #endif diff --git a/content/fetchers/resource.h b/content/fetchers/resource.h index cf4d6edac..8c7b2d10c 100644 --- a/content/fetchers/resource.h +++ b/content/fetchers/resource.h @@ -16,8 +16,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * resource: URL method handler. +/** + * \file + * resource URL scheme handler interface. * * The resource fetcher is intended to provide a flat uniform URL * space for browser local resources referenced by URL. Using this @@ -34,6 +35,8 @@ * Register the resource scheme. * * should only be called from the fetch initialise + * + * \return NSERROR_OK on successful registration or error code on failure. */ nserror fetch_resource_register(void); diff --git a/utils/messages.c b/utils/messages.c index 27038e4e2..c6232979d 100644 --- a/utils/messages.c +++ b/utils/messages.c @@ -200,79 +200,79 @@ const char *messages_get_errorcode(nserror code) { switch (code) { case NSERROR_OK: - /**< No error */ + /* No error */ return messages_get_ctx("OK", messages_hash); case NSERROR_NOMEM: - /**< Memory exhaustion */ + /* Memory exhaustion */ return messages_get_ctx("NoMemory", messages_hash); case NSERROR_NO_FETCH_HANDLER: - /**< No fetch handler for URL scheme */ + /* No fetch handler for URL scheme */ return messages_get_ctx("NoHandler", messages_hash); case NSERROR_NOT_FOUND: - /**< Requested item not found */ + /* Requested item not found */ return messages_get_ctx("NotFound", messages_hash); case NSERROR_SAVE_FAILED: - /**< Failed to save data */ + /* Failed to save data */ return messages_get_ctx("SaveFailed", messages_hash); case NSERROR_CLONE_FAILED: - /**< Failed to clone handle */ + /* Failed to clone handle */ return messages_get_ctx("CloneFailed", messages_hash); case NSERROR_INIT_FAILED: - /**< Initialisation failed */ + /* Initialisation failed */ return messages_get_ctx("InitFailed", messages_hash); case NSERROR_MNG_ERROR: - /**< An MNG error occurred */ + /* An MNG error occurred */ return messages_get_ctx("MNGError", messages_hash); case NSERROR_BAD_ENCODING: - /**< The character set is unknown */ + /* The character set is unknown */ return messages_get_ctx("BadEncoding", messages_hash); case NSERROR_NEED_DATA: - /**< More data needed */ + /* More data needed */ return messages_get_ctx("NeedData", messages_hash); case NSERROR_ENCODING_CHANGE: - /**< The character set encoding change was unhandled */ + /* The character set encoding change was unhandled */ return messages_get_ctx("EncodingChanged", messages_hash); case NSERROR_BAD_PARAMETER: - /**< Bad Parameter */ + /* Bad Parameter */ return messages_get_ctx("BadParameter", messages_hash); case NSERROR_INVALID: - /**< Invalid data */ + /* Invalid data */ return messages_get_ctx("Invalid", messages_hash); case NSERROR_BOX_CONVERT: - /**< Box conversion failed */ + /* Box conversion failed */ return messages_get_ctx("BoxConvert", messages_hash); case NSERROR_STOPPED: - /**< Content conversion stopped */ + /* Content conversion stopped */ return messages_get_ctx("Stopped", messages_hash); case NSERROR_DOM: - /**< DOM call returned error */ + /* DOM call returned error */ return messages_get_ctx("ParsingFail", messages_hash); case NSERROR_CSS: - /**< CSS call returned error */ + /* CSS call returned error */ return messages_get_ctx("CSSGeneric", messages_hash); case NSERROR_CSS_BASE: - /**< CSS base sheet failed */ + /* CSS base sheet failed */ return messages_get_ctx("CSSBase", messages_hash); case NSERROR_BAD_URL: - /**< Bad URL */ + /* Bad URL */ return messages_get_ctx("BadURL", messages_hash); default: @@ -280,6 +280,6 @@ const char *messages_get_errorcode(nserror code) break; } - /**< Unknown error */ + /* Unknown error */ return messages_get_ctx("Unknown", messages_hash); } |