~ubuntu-branches/ubuntu/saucy/apt-cacher-ng/saucy

« back to all changes in this revision

Viewing changes to source/job.cc

  • Committer: Package Import Robot
  • Author(s): Eduard Bloch
  • Date: 2011-09-30 16:37:18 UTC
  • mfrom: (24.2.16 sid)
  • Revision ID: package-import@ubuntu.com-20110930163718-r0agyg6jptvobt5w
* New upstream versions
  + implements extra keeping of obsolete package versions (closes: #634145)
  + configurable outgoing connection protocol (closes: #641257)

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#include "fileitem.h"
14
14
#include "dlcon.h"
15
15
#include "sockio.h"
16
 
#include "fileio.h" // for ::stat
 
16
#include "fileio.h" // for ::stat and related macros
17
17
#include <dirent.h>
18
18
#include <algorithm>
19
19
#include "maintenance.h"
24
24
 
25
25
#include <errno.h>
26
26
 
 
27
// XXX no longer needed after debug logging overhaul
27
28
#define REPLEVEL (m_type==rechecks::FILE_INDEX ? 4 : (m_type==rechecks::FILE_PKG ? 5 : SPAMLEVEL))
28
29
 
29
30
 
53
54
        virtual FiStatus Setup(bool)
54
55
        {
55
56
                m_nSizeChecked = m_nSizeSeen = 0;
56
 
                return status = FIST_INITED;
 
57
                return m_status = FIST_INITED;
57
58
        }
58
59
        virtual void Unreg() {
59
60
                setLockGuard;
60
 
                if(FIST_DLRECEIVING == status)
 
61
                if(FIST_DLRECEIVING == m_status)
61
62
                {
62
63
                        // no shit, there is some input waiting? bring the sender down ASAP
63
64
                        // this is not nice to the sender because it triggers a reconnection, but
64
65
                        // it's a local source so it shouldn't hurt much
65
 
                        status = FIST_ERRNOUSER;
 
66
                        m_status = FIST_ERRNOUSER;
66
67
                        notifyAll();
67
68
                }
68
69
        };
71
72
        {
72
73
                setLockGuard;
73
74
                m_head=h;
74
 
                status=FIST_DLGOTHEAD;
 
75
                m_status=FIST_DLGOTHEAD;
75
76
                return true;
76
77
        }
77
78
        virtual bool StoreFileData(const char *data, unsigned int size)
78
79
        {
79
80
                setLockGuard;
80
81
 
81
 
                LOGSTART2("tPassThroughFitem::StoreFileData", "status: " << status);
 
82
                LOGSTART2("tPassThroughFitem::StoreFileData", "status: " << m_status);
82
83
 
83
84
                // something might care, most likely... also about BOUNCE action
84
85
                notifyAll();
86
87
                m_nIncommingCount += size;
87
88
 
88
89
                dbgline;
89
 
                if (status >= FIST_ERROR || status < FIST_DLGOTHEAD)
 
90
                if (m_status >= FIST_LOCALERROR || m_status < FIST_DLGOTHEAD)
90
91
                        return false;
91
92
 
92
93
                if (size == 0)
93
 
                        status = FIST_COMPLETE;
 
94
                        m_status = FIST_COMPLETE;
94
95
                else
95
96
                {
96
97
                        dbgline;
97
 
                        status = FIST_DLRECEIVING;
 
98
                        m_status = FIST_DLRECEIVING;
98
99
                        m_nSizeChecked += size;
99
100
                        m_pData = data;
100
101
                        m_nConsumable=size;
101
102
                        m_nConsumed=0;
102
 
                        while(0 == m_nConsumed && status<FIST_ERROR)
 
103
                        while(0 == m_nConsumed && m_status<FIST_LOCALERROR)
103
104
                                wait();
104
105
 
105
106
                        dbgline;
106
107
                        // let the downloader abort?
107
 
                        if(status >= FIST_ERROR)
 
108
                        if(m_status >= FIST_LOCALERROR)
108
109
                                return false;
109
110
 
110
111
                        dbgline;
118
119
        {
119
120
                setLockGuard;
120
121
 
121
 
                while(0 == m_nConsumable && status<FIST_ERROR
122
 
                                && ! (m_nSizeChecked==0 && status==FIST_COMPLETE))
 
122
                while(0 == m_nConsumable && m_status<FIST_LOCALERROR
 
123
                                && ! (m_nSizeChecked==0 && m_status==FIST_COMPLETE))
123
124
                {
124
125
                        wait();
125
126
                }
126
 
                if (status >= FIST_ERROR || !m_pData)
 
127
                if (m_status >= FIST_LOCALERROR || !m_pData)
127
128
                        return -1;
128
129
 
129
130
                if(!m_nSizeChecked)
134
135
                        r = 0;
135
136
                if(r<0)
136
137
                {
137
 
                        status=FIST_ERROR;
 
138
                        m_status=FIST_LOCALERROR;
138
139
                }
139
140
                else if(r>0)
140
141
                {
158
159
 
159
160
        tGeneratedFitemBase(const string &sFitemId, const char *szFrontLineMsg) : fileitem(sFitemId), m_data(256)
160
161
        {
161
 
                status=FIST_COMPLETE;
 
162
                m_status=FIST_COMPLETE;
162
163
                m_head.type = header::ANSWER;
163
164
                m_head.frontLine = "HTTP/1.1 ";
164
165
                m_head.frontLine += (szFrontLineMsg ? szFrontLineMsg : "500 Internal Failure");
166
167
        }
167
168
        ssize_t SendData(int out_fd, int, off_t &nSendPos, size_t nMax2SendNow)
168
169
        {
169
 
                if (status >= FIST_ERROR || out_fd<0)
 
170
                if (m_status >= FIST_LOCALERROR || out_fd<0)
170
171
                        return -1;
171
172
                int r = m_data.syswrite(out_fd, nMax2SendNow);
172
173
                if(r>0) nSendPos+=r;
182
183
 
183
184
ssize_t sendfile_generic(int out_fd, int in_fd, off_t *offset, size_t count)
184
185
{
185
 
        LOGSTART("sendfile_generic (fallback)");
186
 
        char buf[4096];
 
186
        char buf[8192];
187
187
        ssize_t totalcnt=0;
188
188
        
189
189
        if(!offset)
251
251
        m_backstate(STATE_TODISCON),
252
252
        m_pReqHead(h),
253
253
        m_nSendPos(0),
254
 
        m_nRangeLast(OFFT_MAX-1), // range size should never overflow
 
254
        m_nRangeLast(MAX_VAL(off_t)-1), // range size should never overflow
255
255
        m_nAllDataCount(0),
256
256
        m_nChunkRemainingBytes(0),
257
 
        m_type(rechecks::FILE_INVALID)
 
257
        m_type(FILE_INVALID)
258
258
{
259
259
        LOGSTART2("job::job", "job creating, " << m_pReqHead->frontLine << " and this: " << uintptr_t(this));
260
260
}
293
293
        return nix;
294
294
}
295
295
 
296
 
void replaceChars(string &s, const char *szBadChars, char goodChar)
297
 
{
298
 
        for(string::iterator p=s.begin();p!=s.end();p++)
299
 
                for(const char *b=szBadChars;*b;b++)
300
 
                        if(*b==*p)
301
 
                        {
302
 
                                *p=goodChar;
303
 
                                break;
304
 
                        }
305
 
}
306
296
 
307
297
inline void job::HandleLocalDownload(const string &visPath,
308
298
                const string &fsBase, const string &fsSubpath)
430
420
                                if(bDir)
431
421
                                        line << "-";
432
422
                                else
433
 
                                        line << stbuf.st_size;
 
423
                                        line << offttosH(stbuf.st_size);
434
424
                        }
435
425
                        closedir(dir);
436
426
                        for(MYSTD::map<string, tSS>::const_iterator it=sortMap.begin(); it!=sortMap.end(); it++)
457
447
                tLocalGetFitem(string s, string sLocalPath, struct stat &stdata) : fileitem(s)
458
448
                {
459
449
                        m_bAllowStoreData=false;
460
 
                        m_sPath=sLocalPath;
461
 
                        status=FIST_COMPLETE;
 
450
                        m_sPathAbs=sLocalPath;
 
451
                        m_status=FIST_COMPLETE;
462
452
                        m_nSizeChecked=m_nSizeSeen=stdata.st_size;
463
453
                        m_bCheckFreshness=false;
464
454
                        m_head.type=header::ANSWER;
484
474
 
485
475
    string sRawUriPath, sPathResdiual;
486
476
    tHttpUrl tUrl; // parsed URL
487
 
        
 
477
 
488
478
    const acfg::tRepoData * pBackends(NULL); // appropriate backends
489
479
    const string * psVname(NULL); // virtual name for storage pool, if available
490
480
    
539
529
                        goto report_invport;
540
530
                }
541
531
 
542
 
                // make a shortcut
543
 
                string & sPath=tUrl.sPath;
544
 
 
545
532
                // kill multiple slashes
546
 
                for(tStrPos pos; stmiss != (pos = sPath.find("//")); )
547
 
                        sPath.erase(pos, 1);
 
533
                for(tStrPos pos; stmiss != (pos = tUrl.sPath.find("//")); )
 
534
                        tUrl.sPath.erase(pos, 1);
548
535
 
549
536
                bPtMode=rechecks::MatchUncacheableRequest(tUrl.ToURI());
550
537
 
577
564
                }
578
565
 
579
566
                // entered directory but not defined as local? Then 404 it with hints
580
 
                if(!sPath.empty() && endsWithSzAr(sPath, "/"))
 
567
                if(!tUrl.sPath.empty() && endsWithSzAr(tUrl.sPath, "/"))
581
568
                {
582
569
                        LOG("generic user information page");
583
570
                        m_sMaintCmd="/";
584
571
                        return;
585
572
                }
586
573
 
587
 
                m_type = rechecks::GetFiletype(sPath);
 
574
                m_type = rechecks::GetFiletype(tUrl.sPath);
588
575
 
589
 
                if ( m_type == rechecks::FILE_INVALID ) goto report_notallowed;
 
576
                if ( m_type == FILE_INVALID ) goto report_notallowed;
590
577
                
591
578
                // got something valid, has type now, trace it
592
579
                USRDBG(REPLEVEL, "Processing new job, "<<m_pReqHead->frontLine);
598
585
                        m_sFileLoc=*psVname+SZPATHSEP+sPathResdiual;
599
586
                else
600
587
                        m_sFileLoc=tUrl.sHost+tUrl.sPath;
601
 
                
602
 
                // FIXME: this sucks, belongs into the fileitem
603
 
                if(acfg::stupidfs)
604
 
                {
605
 
                        // fix weird chars that we don't like in the filesystem
606
 
                        replaceChars(tUrl.sPath, ENEMIESOFDOSFS, '_');
607
 
                        replaceChars(tUrl.sHost, ENEMIESOFDOSFS, '_');
608
 
#ifdef WIN32
609
 
                        replaceChars(tUrl.sPath, "/", '\\');
610
 
#endif
611
 
                }
 
588
 
 
589
                bForceFreshnessChecks = ( ! acfg::offlinemode && m_type==FILE_INDEX);
 
590
 
 
591
        m_pItem=fileitem::GetRegisteredFileItem(m_sFileLoc);
 
592
 
612
593
        }
613
594
        MYCATCH(MYSTD::out_of_range&) // better safe...
614
595
        {
615
596
        goto report_invpath;
616
597
    }
617
598
    
618
 
    bForceFreshnessChecks = ( ! acfg::offlinemode && m_type==rechecks::FILE_INDEX);
619
 
 
620
 
#ifdef QUATSCH
621
 
    // some users want to not be most up-to-date
622
 
        if(bForceFreshnessChecks && acfg::updinterval > 0)
623
 
        {
624
 
                struct stat stbuf;
625
 
                bForceFreshnessChecks=(0 == ::stat(m_sFileLoc.c_str(), &stbuf)
626
 
                                && ( time(0) - (UINT) stbuf.st_ctime) < acfg::updinterval);
627
 
        }
628
 
#endif
629
 
 
630
 
        m_pItem=fileitem::GetFileItem(m_sFileLoc);
631
 
    
632
599
    if(!m_pItem)
633
600
    {
634
 
        if(acfg::debug)
635
 
                aclog::err(string("Error creating file item for ")+m_sFileLoc);
 
601
        USRDBG(nix, "Error creating file item for " << m_sFileLoc);
636
602
        goto report_overload;
637
603
    }
638
604
    
655
621
        dbgline;
656
622
        if(!m_pParentCon->SetupDownloader(m_pReqHead->h[header::XFORWARDEDFOR]))
657
623
        {
658
 
                if(acfg::debug)
659
 
                        aclog::err(string("Error creating download handler for ")+m_sFileLoc);
 
624
                USRDBG(x, "Error creating download handler for "<<m_sFileLoc);
660
625
                goto report_overload;
661
626
        }
662
627
        
663
628
        dbgline;
664
629
        MYTRY
665
630
                {
666
 
                        if(psVname && NULL != (pBackends=acfg::GetBackendVec(psVname)))
 
631
                        if(psVname && NULL != (pBackends=acfg::GetBackendVec(*psVname)))
667
632
                        {
668
633
                                LOG("Backends found, using them with " << sPathResdiual
669
634
                                                << ", first backend: " <<pBackends->m_backends.front().ToURI());
691
656
                }
692
657
                MYCATCH(MYSTD::bad_alloc&) // OOM, may this ever happen here?
693
658
                {
694
 
                        if(acfg::debug)
695
 
                                aclog::err("Out of memory");                                    
 
659
                        USRDBG(y, "Out of memory");
696
660
                        goto report_overload;
697
661
                };
698
662
        }
739
703
        }
740
704
        
741
705
        off_t nGooddataSize(0);
742
 
        FiStatus fistate(FIST_ERROR);
 
706
        FiStatus fistate(FIST_LOCALERROR);
743
707
        header respHead; // template of the response header, e.g. as found in cache
744
708
 
745
709
        if (confd<0)
754
718
                        fistate=m_pItem->GetStatusUnlocked(nGooddataSize);
755
719
                        
756
720
                        dbgline;
757
 
                        if (fistate>=FIST_ERROR)
 
721
                        if (fistate>=FIST_LOCALERROR)
758
722
                        {
759
723
                                const header &h = m_pItem->GetHeaderUnlocked();
760
724
                                g.unLock(); // item lock must be released in order to replace it!
990
954
                }
991
955
                else if (httpstatus >= 300)
992
956
                {
993
 
                        bHasSendableData = ( (respHead.h[header::CONTENT_LENGTH]
994
 
                                                         && atoi(respHead.h[header::CONTENT_LENGTH])>0)
995
 
                                        || bChunked);
 
957
                        bHasSendableData = atoofft(respHead.h[header::CONTENT_LENGTH], 0) || bChunked;
996
958
                }
997
959
        }
998
960
 
1023
985
                                        m_pReqHead->h[header::IFRANGE] : m_pReqHead->h[header::IF_MODIFIED_SINCE];
1024
986
 
1025
987
                        // consider contents "fresh" for non-volatile data, or when "our" special client is there, or the client simply doesn't care
1026
 
                        bool bFreshnessForced = (m_type != rechecks::FILE_INDEX
 
988
                        bool bFreshnessForced = (m_type != FILE_INDEX
1027
989
                                || m_pReqHead->h[header::ACNGFSMARK] || !pIfmo);
1028
990
 
1029
991
                        // this plays well with lighttpd <-> Apt, but may not work with the alternative time format
1161
1123
}
1162
1124
 
1163
1125
 
1164
 
void job::SetErrorResponse(const char * errorLine, int nMinUserLogLevel)
 
1126
void job::SetErrorResponse(const char * errorLine)
1165
1127
{
1166
1128
        LOGSTART2("job::SetErrorResponse", errorLine);
1167
1129